summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin F. Haggerty <haggertk@lineageos.org>2020-06-01 21:27:32 -0600
committerKevin F. Haggerty <haggertk@lineageos.org>2020-06-01 21:27:32 -0600
commitf3cc53f681a9bac4055d898768ed71ffc765aff3 (patch)
tree1e4c66195315151ce29346a39ee66d0aed884e35
parent5e736f33078be0c2b73deb2ca4b695c7b53ebbe4 (diff)
parent225ed537cd29d874bfb50fb4c8a5f69b33756bc0 (diff)
downloadandroid_system_bt-lineage-17.1.tar.gz
android_system_bt-lineage-17.1.tar.bz2
android_system_bt-lineage-17.1.zip
Merge tag 'android-10.0.0_r37' into staging/lineage-17.1_merge-android-10.0.0_r37lineage-17.1
Android 10.0.0 Release 37 (QQ3A.200605.001) * tag 'android-10.0.0_r37': (29 commits) Check a2dp packet length is zero DO NOT MERGE Fix potential overflow in btif_rc Revert "DO NOT MERGE Ensure hci command status event has sufficient packet length" Fix potential stack overflow caused by integer overflow Fix potential stack overflow caused by integer overflow Fix potential OOB vulnerability when an HCI event is received HF_Client: Send BTA_HF_CLIENT_RFC_CLOSE_EVT when client_cb == NULL HF_Client: Free the RFC if the handle doesn't match Notify remote name failed for LE device DO NOT MERGE Ensure hci command status event has sufficient packet length AVRCP Controller manage focus while disconnected AVRCP Controller refresh track data on Interim AVRCP Controller get play status ServiceDiscoveryProtocol DB Full AVRCP Position Changed Notification DO NOT MERGE: AVRCP Controller Shuffle/Repeat support GattServcer: Check invalid offset GattServcer: Check invalid offset avrc: Validating msg size before accessing fields btm: fixing oob write in multi-adv SetData. ... Change-Id: Idbf5d77879ca2d30a9d8fbb56880b0db7d7aa97d
-rw-r--r--TEST_MAPPING4
-rw-r--r--binder/android/bluetooth/IBluetoothManager.aidl2
-rw-r--r--bta/av/bta_av_aact.cc3
-rw-r--r--bta/av/bta_av_ssm.cc2
-rw-r--r--bta/hf_client/bta_hf_client_rfc.cc5
-rw-r--r--btif/Android.bp33
-rw-r--r--btif/src/btif_a2dp_sink.cc1
-rw-r--r--btif/src/btif_rc.cc33
-rw-r--r--btif/test/btif_rc_test.cc131
-rw-r--r--internal_include/bt_target.h2
-rw-r--r--profile/avrcp/device.cc23
-rw-r--r--stack/Android.bp1
-rw-r--r--stack/BUILD.gn1
-rw-r--r--stack/avdt/avdt_msg.cc30
-rw-r--r--stack/avrc/avrc_pars_ct.cc2
-rw-r--r--stack/avrc/avrc_pars_tg.cc52
-rw-r--r--stack/btm/btm_ble_multi_adv.cc15
-rw-r--r--stack/btm/btm_inq.cc21
-rw-r--r--stack/btm/btm_int.h2
-rw-r--r--stack/btu/btu_hcif.cc8
-rw-r--r--stack/crypto_toolbox/aes_cmac.cc3
-rw-r--r--stack/include/hci_evt_length.h278
-rw-r--r--stack/test/stack_avrcp_test.cc112
23 files changed, 710 insertions, 54 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 5f6e37861..8b050569b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -76,6 +76,10 @@
{
"name" : "net_test_types",
"host" : true
+ },
+ {
+ "name" : "net_test_btif_rc",
+ "host" : true
}
]
}
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
index 2e1270048..8a80d4991 100644
--- a/binder/android/bluetooth/IBluetoothManager.aidl
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -46,6 +46,8 @@ interface IBluetoothManager
String getAddress();
String getName();
+ boolean onFactoryReset();
+
boolean isBleScanAlwaysAvailable();
int updateBleAppCount(IBinder b, boolean enable, String packageName);
boolean isBleAppPresent();
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index b022b43af..7cd70561c 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -1246,7 +1246,6 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_SUCCESS;
- open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
p = BTM_ReadRemoteFeatures(p_scb->PeerAddress());
if (p != NULL) {
@@ -1262,8 +1261,10 @@ void bta_av_str_opened(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr, p_scb->hdi);
#endif
if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) {
+ open.starting = false;
open.sep = AVDT_TSEP_SNK;
} else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK) {
+ open.starting = bta_av_chk_start(p_scb);
open.sep = AVDT_TSEP_SRC;
}
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index a1a94b0e3..80effa372 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -329,7 +329,7 @@ static const uint8_t bta_av_sst_open[][BTA_AV_NUM_COLS] = {
/* STR_RECONFIG_CFM_EVT */
{BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVRC_TIMER_EVT */
- {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST},
+ {BTA_AV_OPEN_RC, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_DISCONNECT_EVT */
{BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
diff --git a/bta/hf_client/bta_hf_client_rfc.cc b/bta/hf_client/bta_hf_client_rfc.cc
index f3e0947eb..535371f6b 100644
--- a/bta/hf_client/bta_hf_client_rfc.cc
+++ b/bta/hf_client/bta_hf_client_rfc.cc
@@ -127,6 +127,7 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
} else {
APPL_TRACE_ERROR("%s: PORT_SUCCESS, ignoring handle = %d", __func__,
port_handle);
+ osi_free(p_buf);
return;
}
} else if (client_cb != NULL &&
@@ -136,6 +137,10 @@ static void bta_hf_client_mgmt_cback(uint32_t code, uint16_t port_handle) {
RFCOMM_RemoveServer(port_handle);
p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
+ } else if (client_cb == NULL) {
+ // client_cb is already cleaned due to hfp client disabled.
+ // Assigned a valid event value to header and send this message anyway.
+ p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
}
p_buf->hdr.layer_specific = client_cb != NULL ? client_cb->handle : 0;
diff --git a/btif/Android.bp b/btif/Android.bp
index f33d174cf..0ecf20792 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -208,3 +208,36 @@ cc_test {
],
cflags: ["-DBUILDCFG"],
}
+
+// btif rc unit tests for target
+// ========================================================
+cc_test {
+ name: "net_test_btif_rc",
+ defaults: ["fluoride_defaults"],
+ test_suites: ["device-tests"],
+ host_supported: true,
+ include_dirs: btifCommonIncludes,
+ srcs: [
+ "test/btif_rc_test.cc",
+ ],
+ header_libs: ["libbluetooth_headers"],
+ shared_libs: [
+ "libcrypto",
+ "libcutils",
+ "liblog",
+ "libprotobuf-cpp-lite",
+ ],
+ static_libs: [
+ "libbluetooth-types",
+ "libbt-common",
+ "libbt-protos-lite",
+ "libosi",
+ "libosi-AllocationTestHarness",
+ ],
+ cflags: ["-DBUILDCFG"],
+ sanitize: {
+ address: true,
+ cfi: true,
+ misc_undefined: ["bounds"],
+ },
+}
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index bb1bc49c0..aa75d21d4 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -667,7 +667,6 @@ static void btif_a2dp_sink_set_focus_state_event(
LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
LockGuard lock(g_mutex);
- if (!btif_av_is_connected()) return;
APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
btif_a2dp_sink_cb.rx_focus_state = state;
if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 9919a7b42..575d83e37 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -1836,6 +1836,12 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr,
BTIF_TRACE_DEBUG("%s", __func__);
CHECK_RC_CONNECTED(p_dev);
+ if (num_attr > BTRC_MAX_ELEM_ATTR_SIZE) {
+ LOG(WARNING) << __func__
+ << " Exceeded number attributes:" << static_cast<int>(num_attr)
+ << " max:" << BTRC_MAX_ELEM_ATTR_SIZE;
+ num_attr = BTRC_MAX_ELEM_ATTR_SIZE;
+ }
memset(element_attrs, 0, sizeof(tAVRC_ATTR_ENTRY) * num_attr);
if (num_attr == 0) {
@@ -1844,7 +1850,8 @@ static bt_status_t get_element_attr_rsp(const RawAddress& bd_addr,
for (i = 0; i < num_attr; i++) {
element_attrs[i].attr_id = p_attrs[i].attr_id;
element_attrs[i].name.charset_id = AVRC_CHARSET_ID_UTF8;
- element_attrs[i].name.str_len = (uint16_t)strlen((char*)p_attrs[i].text);
+ element_attrs[i].name.str_len =
+ (uint16_t)strnlen((char*)p_attrs[i].text, BTRC_MAX_ATTR_STR_LEN);
element_attrs[i].name.p_str = p_attrs[i].text;
BTIF_TRACE_DEBUG(
"%s: attr_id: 0x%x, charset_id: 0x%x, str_len: %d, str: %s", __func__,
@@ -2939,11 +2946,12 @@ static void register_for_event_notification(btif_rc_supported_event_t* p_event,
return;
}
// interval is only valid for AVRC_EVT_PLAY_POS_CHANGED
- uint32_t interval = 0;
+ uint32_t interval_in_seconds = 0;
if (p_event->event_id == AVRC_EVT_PLAY_POS_CHANGED) {
- interval = 2000;
+ interval_in_seconds = 2;
}
- status = register_notification_cmd(p_transaction->lbl, p_event->event_id, interval, p_dev);
+ status = register_notification_cmd(p_transaction->lbl, p_event->event_id,
+ interval_in_seconds, p_dev);
if (status != BT_STATUS_SUCCESS) {
BTIF_TRACE_ERROR("%s: Error in Notification registration: %d", __func__,
status);
@@ -3152,11 +3160,10 @@ static void handle_notification_response(tBTA_AV_META_MSG* pmeta_msg,
break;
} else {
uint8_t* p_data = p_rsp->param.track;
- /* Update the UID for current track
- * Attributes will be fetched after the AVRCP procedure
- */
BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
get_play_status_cmd(p_dev);
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list,
+ p_dev);
}
break;
@@ -3336,6 +3343,8 @@ static void handle_app_attr_response(tBTA_AV_META_MSG* pmeta_msg,
rc_ctrl_procedure_complete(p_dev);
return;
}
+ p_dev->rc_app_settings.num_attrs = 0;
+ p_dev->rc_app_settings.num_ext_attrs = 0;
for (xx = 0; xx < p_rsp->num_attr; xx++) {
uint8_t st_index;
@@ -3809,6 +3818,10 @@ static void handle_get_playstatus_response(tBTA_AV_META_MSG* pmeta_msg,
if (p_rsp->status == AVRC_STS_NO_ERROR) {
do_in_jni_thread(
FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, p_dev->rc_addr,
+ (btrc_play_status_t)p_rsp->play_status));
+ do_in_jni_thread(
+ FROM_HERE,
base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb,
p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos));
} else {
@@ -3907,6 +3920,12 @@ static void handle_get_folder_items_response(tBTA_AV_META_MSG* pmeta_msg,
/* We want to make the ownership explicit in native */
btrc_items, item_count));
+ if (item_count > 0) {
+ if (btrc_items[0].item_type == AVRC_ITEM_PLAYER &&
+ (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING)) {
+ list_player_app_setting_attrib_cmd(p_dev);
+ }
+ }
/* Release the memory block for items and attributes allocated here.
* Since the executor for do_in_jni_thread is a Single Thread Task Runner it
* is okay to queue up the cleanup of btrc_items */
diff --git a/btif/test/btif_rc_test.cc b/btif/test/btif_rc_test.cc
new file mode 100644
index 000000000..6271881c9
--- /dev/null
+++ b/btif/test/btif_rc_test.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <cstdint>
+
+#include "bta/include/bta_av_api.h"
+#include "btif/include/btif_common.h"
+#include "device/include/interop.h"
+#include "include/hardware/bt_rc.h"
+#include "osi/test/AllocationTestHarness.h"
+#include "stack/include/btm_api_types.h"
+#include "types/raw_address.h"
+#undef LOG_TAG
+#include "btif/src/btif_rc.cc"
+
+extern void allocation_tracker_uninit(void);
+
+namespace {
+int AVRC_BldResponse_ = 0;
+} // namespace
+
+uint8_t appl_trace_level = BT_TRACE_LEVEL_WARNING;
+uint8_t btif_trace_level = BT_TRACE_LEVEL_WARNING;
+
+tAVRC_STS AVRC_BldCommand(tAVRC_COMMAND* p_cmd, BT_HDR** pp_pkt) { return 0; }
+tAVRC_STS AVRC_BldResponse(uint8_t handle, tAVRC_RESPONSE* p_rsp,
+ BT_HDR** pp_pkt) {
+ AVRC_BldResponse_++;
+ return 0;
+}
+tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
+ return 0;
+}
+tAVRC_STS AVRC_Ctrl_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ uint8_t* p_buf, uint16_t* buf_len) {
+ return 0;
+}
+tAVRC_STS AVRC_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result,
+ uint8_t* p_buf, uint16_t buf_len) {
+ return 0;
+}
+tAVRC_STS AVRC_ParsResponse(tAVRC_MSG* p_msg, tAVRC_RESPONSE* p_result,
+ UNUSED_ATTR uint8_t* p_buf,
+ UNUSED_ATTR uint16_t buf_len) {
+ return 0;
+}
+void BTA_AvCloseRc(uint8_t rc_handle) {}
+void BTA_AvMetaCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CMD cmd_code,
+ BT_HDR* p_pkt) {}
+void BTA_AvMetaRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ BT_HDR* p_pkt) {}
+void BTA_AvRemoteCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_RC rc_id,
+ tBTA_AV_STATE key_state) {}
+void BTA_AvRemoteVendorUniqueCmd(uint8_t rc_handle, uint8_t label,
+ tBTA_AV_STATE key_state, uint8_t* p_msg,
+ uint8_t buf_len) {}
+void BTA_AvVendorCmd(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE cmd_code,
+ uint8_t* p_data, uint16_t len) {}
+void BTA_AvVendorRsp(uint8_t rc_handle, uint8_t label, tBTA_AV_CODE rsp_code,
+ uint8_t* p_data, uint16_t len, uint32_t company_id) {}
+void btif_av_clear_remote_suspend_flag(void) {}
+bool btif_av_is_connected(void) { return false; }
+bool btif_av_is_sink_enabled(void) { return false; }
+RawAddress btif_av_sink_active_peer(void) { return RawAddress(); }
+RawAddress btif_av_source_active_peer(void) { return RawAddress(); }
+bool btif_av_stream_started_ready(void) { return false; }
+bt_status_t btif_transfer_context(tBTIF_CBACK* p_cback, uint16_t event,
+ char* p_params, int param_len,
+ tBTIF_COPY_CBACK* p_copy_cback) {
+ return BT_STATUS_SUCCESS;
+}
+const char* dump_rc_event(uint8_t event) { return nullptr; }
+const char* dump_rc_notification_event_id(uint8_t event_id) { return nullptr; }
+const char* dump_rc_pdu(uint8_t pdu) { return nullptr; }
+bt_status_t do_in_jni_thread(const base::Location& from_here,
+ base::OnceClosure task) {
+ return BT_STATUS_SUCCESS;
+}
+base::MessageLoop* get_main_message_loop() { return nullptr; }
+bool interop_match_addr(const interop_feature_t feature,
+ const RawAddress* addr) {
+ return false;
+}
+void LogMsg(uint32_t trace_set_mask, const char* fmt_str, ...) {}
+
+/**
+ * Test class to test selected functionality in hci/src/hci_layer.cc
+ */
+class BtifRcTest : public AllocationTestHarness {
+ protected:
+ void SetUp() override {
+ AllocationTestHarness::SetUp();
+ // Disable our allocation tracker to allow ASAN full range
+ allocation_tracker_uninit();
+ }
+
+ void TearDown() override { AllocationTestHarness::TearDown(); }
+};
+
+TEST_F(BtifRcTest, get_element_attr_rsp) {
+ RawAddress bd_addr;
+
+ btif_rc_cb.rc_multi_cb[0].rc_addr = bd_addr;
+ btif_rc_cb.rc_multi_cb[0].rc_connected = true;
+ btif_rc_cb.rc_multi_cb[0]
+ .rc_pdu_info[IDX_GET_ELEMENT_ATTR_RSP]
+ .is_rsp_pending = true;
+ btif_rc_cb.rc_multi_cb[0].rc_state = BTRC_CONNECTION_STATE_CONNECTED;
+
+ btrc_element_attr_val_t p_attrs[BTRC_MAX_ELEM_ATTR_SIZE];
+ uint8_t num_attr = BTRC_MAX_ELEM_ATTR_SIZE + 1;
+
+ CHECK(get_element_attr_rsp(bd_addr, num_attr, p_attrs) == BT_STATUS_SUCCESS);
+ CHECK(AVRC_BldResponse_ == 1);
+}
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index b1227a345..e33f0b580 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -108,7 +108,7 @@
#endif
#ifndef BTA_DM_SDP_DB_SIZE
-#define BTA_DM_SDP_DB_SIZE 8000
+#define BTA_DM_SDP_DB_SIZE 20000
#endif
#ifndef HL_INCLUDED
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index 4ca624b81..264eaf04c 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -98,6 +98,19 @@ void Device::VendorPacketHandler(uint8_t label,
case CommandPdu::REGISTER_NOTIFICATION: {
auto register_notification =
Packet::Specialize<RegisterNotificationResponse>(pkt);
+
+ if (!register_notification->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response =
+ RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
+ Status::INVALID_PARAMETER);
+ send_message(label, false, std::move(response));
+ active_labels_.erase(label);
+ volume_interface_ = nullptr;
+ volume_ = VOL_REGISTRATION_FAILED;
+ return;
+ }
+
if (register_notification->GetEvent() != Event::VOLUME_CHANGED) {
DEVICE_LOG(WARNING)
<< __func__ << ": Unhandled register notification received: "
@@ -336,16 +349,6 @@ void Device::HandleVolumeChanged(
uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt) {
DEVICE_VLOG(1) << __func__ << ": interim=" << pkt->IsInterim();
- if (!pkt->IsValid()) {
- DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
- auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
- send_message(label, false, std::move(response));
- active_labels_.erase(label);
- volume_interface_ = nullptr;
- volume_ = VOL_REGISTRATION_FAILED;
- return;
- }
-
if (volume_interface_ == nullptr) return;
if (pkt->GetCType() == CType::REJECTED) {
diff --git a/stack/Android.bp b/stack/Android.bp
index f7f5a4532..f9d11e21d 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -200,6 +200,7 @@ cc_test {
],
srcs: [
"test/stack_a2dp_test.cc",
+ "test/stack_avrcp_test.cc",
],
shared_libs: [
"libcrypto",
diff --git a/stack/BUILD.gn b/stack/BUILD.gn
index 00680c85e..87dc72639 100644
--- a/stack/BUILD.gn
+++ b/stack/BUILD.gn
@@ -202,6 +202,7 @@ executable("stack_unittests") {
testonly = true
sources = [
"test/stack_a2dp_test.cc",
+ "test/stack_avrcp_test.cc",
]
include_dirs = [
diff --git a/stack/avdt/avdt_msg.cc b/stack/avdt/avdt_msg.cc
index 853f36985..33fbfa744 100644
--- a/stack/avdt/avdt_msg.cc
+++ b/stack/avdt/avdt_msg.cc
@@ -985,18 +985,30 @@ static uint8_t avdt_msg_prs_security_rsp(tAVDT_MSG* p_msg, uint8_t* p,
* Returns Error code or zero if no error.
*
******************************************************************************/
-static uint8_t avdt_msg_prs_rej(tAVDT_MSG* p_msg, uint8_t* p, uint8_t sig) {
- if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) {
- p_msg->hdr.err_param = *p++;
- p_msg->hdr.err_code = *p;
- } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) {
- AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
- p_msg->hdr.err_code = *p;
+static uint8_t avdt_msg_prs_rej(tAVDT_MSG* p_msg, uint8_t* p, uint16_t len,
+ uint8_t sig) {
+ uint8_t error = 0;
+
+ if (len > 0) {
+ if ((sig == AVDT_SIG_SETCONFIG) || (sig == AVDT_SIG_RECONFIG)) {
+ p_msg->hdr.err_param = *p++;
+ len--;
+ } else if ((sig == AVDT_SIG_START) || (sig == AVDT_SIG_SUSPEND)) {
+ AVDT_MSG_PRS_SEID(p, p_msg->hdr.err_param);
+ len--;
+ }
+ }
+
+ if (len < 1) {
+ char error_info[] = "AVDT rejected response length mismatch";
+ android_errorWriteWithInfoLog(0x534e4554, "79702484", -1, error_info,
+ strlen(error_info));
+ error = AVDT_ERR_LENGTH;
} else {
p_msg->hdr.err_code = *p;
}
- return 0;
+ return error;
}
/*******************************************************************************
@@ -1604,7 +1616,7 @@ void avdt_msg_ind(AvdtpCcb* p_ccb, BT_HDR* p_buf) {
evt = avdt_msg_rsp_2_evt[sig - 1];
} else /* msg_type == AVDT_MSG_TYPE_REJ */
{
- err = avdt_msg_prs_rej(&msg, p, sig);
+ err = avdt_msg_prs_rej(&msg, p, p_buf->len, sig);
evt = avdt_msg_rej_2_evt[sig - 1];
}
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index 80dc882da..39ed921d9 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -806,7 +806,7 @@ static tAVRC_STS avrc_ctrl_pars_vendor_rsp(tAVRC_MSG_VENDOR* p_msg,
if (len < min_len) goto length_error;
BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
- BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p);
break;
case AVRC_PDU_SET_ADDRESSED_PLAYER:
diff --git a/stack/avrc/avrc_pars_tg.cc b/stack/avrc/avrc_pars_tg.cc
index 22471bda5..fe1db3dbc 100644
--- a/stack/avrc/avrc_pars_tg.cc
+++ b/stack/avrc/avrc_pars_tg.cc
@@ -363,7 +363,7 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR* p_msg,
*
* Description This function is used to parse cmds received for CTRL
* Currently it is for SetAbsVolume and Volume Change
- * Notification..
+ * Notification.
*
* Returns AVRC_STS_NO_ERROR, if the message in p_data is parsed
* successfully.
@@ -390,6 +390,12 @@ tAVRC_STS AVRC_Ctrl_ParsCommand(tAVRC_MSG* p_msg, tAVRC_COMMAND* p_result) {
return status;
}
+#define RETURN_STATUS_IF_FALSE(_status_, _b_, _msg_, ...) \
+ if (!(_b_)) { \
+ AVRC_TRACE_DEBUG(_msg_, ##__VA_ARGS__); \
+ return _status_; \
+ }
+
/*******************************************************************************
*
* Function avrc_pars_browsing_cmd
@@ -409,6 +415,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
uint8_t* p = p_msg->p_browse_data;
int count;
+ uint16_t min_len = 3;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
p_result->pdu = *p++;
AVRC_TRACE_DEBUG("avrc_pars_browsing_cmd() pdu:0x%x", p_result->pdu);
/* skip over len */
@@ -416,11 +426,20 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
switch (p_result->pdu) {
case AVRC_PDU_SET_BROWSED_PLAYER: /* 0x70 */
+ min_len += 2;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
// For current implementation all players are browsable.
BE_STREAM_TO_UINT16(p_result->br_player.player_id, p);
break;
case AVRC_PDU_GET_FOLDER_ITEMS: /* 0x71 */
+
+ min_len += 10;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
STREAM_TO_UINT8(p_result->get_items.scope, p);
// To be modified later here (Scope) when all browsing commands are
// supported
@@ -441,12 +460,21 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
if (buf_len < (count << 2))
p_result->get_items.attr_count = count = (buf_len >> 2);
for (int idx = 0; idx < count; idx++) {
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
+ (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT32(p_result->get_items.p_attr_list[idx], p);
}
}
break;
case AVRC_PDU_CHANGE_PATH: /* 0x72 */
+ min_len += 11;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT16(p_result->chg_path.uid_counter, p);
BE_STREAM_TO_UINT8(p_result->chg_path.direction, p);
if (p_result->chg_path.direction != AVRC_DIR_UP &&
@@ -457,7 +485,12 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_GET_ITEM_ATTRIBUTES: /* 0x73 */
+ min_len += 12;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT8(p_result->get_attrs.scope, p);
+
if (p_result->get_attrs.scope > AVRC_SCOPE_NOW_PLAYING) {
status = AVRC_STS_BAD_SCOPE;
break;
@@ -473,6 +506,11 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
p_result->get_attrs.attr_count = count = (buf_len >> 2);
for (int idx = 0, count = 0; idx < p_result->get_attrs.attr_count;
idx++) {
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD,
+ (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT32(p_result->get_attrs.p_attr_list[count], p);
if (AVRC_IS_VALID_MEDIA_ATTRIBUTE(
p_result->get_attrs.p_attr_list[count])) {
@@ -488,6 +526,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS: /* 0x75 */
+ ++min_len;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT8(p_result->get_num_of_items.scope, p);
if (p_result->get_num_of_items.scope > AVRC_SCOPE_NOW_PLAYING) {
status = AVRC_STS_BAD_SCOPE;
@@ -495,6 +537,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
break;
case AVRC_PDU_SEARCH: /* 0x80 */
+ min_len += 4;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_UINT16(p_result->search.string.charset_id, p);
BE_STREAM_TO_UINT16(p_result->search.string.str_len, p);
p_result->search.string.p_str = p_buf;
@@ -504,6 +550,10 @@ static tAVRC_STS avrc_pars_browsing_cmd(tAVRC_MSG_BROWSE* p_msg,
} else {
android_errorWriteLog(0x534e4554, "63146237");
}
+ min_len += p_result->search.string.str_len;
+ RETURN_STATUS_IF_FALSE(AVRC_STS_BAD_CMD, (p_msg->browse_len >= min_len),
+ "msg too short");
+
BE_STREAM_TO_ARRAY(p, p_buf, p_result->search.string.str_len);
} else {
status = AVRC_STS_INTERNAL_ERR;
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index 22d2e176a..b425c0927 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -728,16 +728,13 @@ class BleAdvertisingManagerImpl
data.insert(data.begin(), flags.begin(), flags.end());
}
- // Find and fill TX Power with the correct value
- if (data.size()) {
- size_t i = 0;
- while (i < data.size()) {
- uint8_t type = data[i + 1];
- if (type == HCI_EIR_TX_POWER_LEVEL_TYPE) {
- data[i + 2] = adv_inst[inst_id].tx_power;
- }
- i += data[i] + 1;
+ // Find and fill TX Power with the correct value.
+ // The TX Power section is a 3 byte section.
+ for (size_t i = 0; (i + 2) < data.size();) {
+ if (data[i + 1] == HCI_EIR_TX_POWER_LEVEL_TYPE) {
+ data[i + 2] = adv_inst[inst_id].tx_power;
}
+ i += data[i] + 1;
}
VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size());
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index ef163596a..f56369b4b 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -915,10 +915,9 @@ tBTM_STATUS BTM_CancelRemoteDeviceName(void) {
/* Make sure there is not already one in progress */
if (p_inq->remname_active) {
if (BTM_UseLeLink(p_inq->remname_bda)) {
- if (btm_ble_cancel_remote_name(p_inq->remname_bda))
- return (BTM_CMD_STARTED);
- else
- return (BTM_UNKNOWN_ADDR);
+ /* Cancel remote name request for LE device, and process remote name
+ * callback. */
+ btm_inq_rmt_name_failed_cancelled();
} else
btsnd_hcic_rmt_name_req_cancel(p_inq->remname_bda);
return (BTM_CMD_STARTED);
@@ -2091,22 +2090,22 @@ void btm_process_remote_name(const RawAddress* bda, BD_NAME bdn,
}
void btm_inq_remote_name_timer_timeout(UNUSED_ATTR void* data) {
- btm_inq_rmt_name_failed();
+ btm_inq_rmt_name_failed_cancelled();
}
/*******************************************************************************
*
- * Function btm_inq_rmt_name_failed
+ * Function btm_inq_rmt_name_failed_cancelled
*
- * Description This function is if timeout expires while getting remote
- * name. This is done for devices that incorrectly do not
- * report operation failure
+ * Description This function is if timeout expires or request is cancelled
+ * while getting remote name. This is done for devices that
+ * incorrectly do not report operation failure
*
* Returns void
*
******************************************************************************/
-void btm_inq_rmt_name_failed(void) {
- BTM_TRACE_ERROR("btm_inq_rmt_name_failed() remname_active=%d",
+void btm_inq_rmt_name_failed_cancelled(void) {
+ BTM_TRACE_ERROR("btm_inq_rmt_name_failed_cancelled() remname_active=%d",
btm_cb.btm_inq_vars.remname_active);
if (btm_cb.btm_inq_vars.remname_active)
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index 88cb72420..05180db5e 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -59,7 +59,7 @@ extern tBTM_STATUS btm_initiate_rem_name(const RawAddress& remote_bda,
extern void btm_process_remote_name(const RawAddress* bda, BD_NAME name,
uint16_t evt_len, uint8_t hci_status);
-extern void btm_inq_rmt_name_failed(void);
+extern void btm_inq_rmt_name_failed_cancelled(void);
extern void btm_inq_remote_name_timer_timeout(void* data);
/* Inquiry related functions */
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index 245c537fb..52d5d60f8 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -48,6 +48,7 @@
#include "btu.h"
#include "common/metrics.h"
#include "device/include/controller.h"
+#include "hci_evt_length.h"
#include "hci_layer.h"
#include "hcimsgs.h"
#include "l2c_int.h"
@@ -257,6 +258,13 @@ void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id, BT_HDR* p_msg) {
STREAM_TO_UINT8(hci_evt_code, p);
STREAM_TO_UINT8(hci_evt_len, p);
+ // validate event size
+ if (hci_evt_len < hci_event_parameters_minimum_length[hci_evt_code]) {
+ HCI_TRACE_WARNING("%s: evt:0x%2X, malformed event of size %hhd", __func__,
+ hci_evt_code, hci_evt_len);
+ return;
+ }
+
btu_hcif_log_event_metrics(hci_evt_code, p);
switch (hci_evt_code) {
diff --git a/stack/crypto_toolbox/aes_cmac.cc b/stack/crypto_toolbox/aes_cmac.cc
index 8b8246e87..c90b80ce1 100644
--- a/stack/crypto_toolbox/aes_cmac.cc
+++ b/stack/crypto_toolbox/aes_cmac.cc
@@ -180,7 +180,8 @@ static void cmac_generate_subkey(const Octet16& key) {
* length - length of the input in byte.
*/
Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
- uint16_t len, diff;
+ uint32_t len;
+ uint16_t diff;
/* n is number of rounds */
uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
diff --git a/stack/include/hci_evt_length.h b/stack/include/hci_evt_length.h
new file mode 100644
index 000000000..ea8dfdff1
--- /dev/null
+++ b/stack/include/hci_evt_length.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2020 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.
+ */
+
+/*
+ * Definitions for HCI Event Parameter Minimum Length
+ */
+static const uint8_t hci_event_parameters_minimum_length[] = {
+ 0, // 0x00 - N/A
+ 1, // 0x01 - HCI_Inquiry_Complete Event
+ 15, // 0x02 - HCI_Inquiry_Result Event (Num_Responses = 1)
+ 11, // 0x03 - HCI_Connection_Complete Event
+ 10, // 0x04 - HCI_Connection_Request Event
+ 4, // 0x05 - HCI_Disconnection_Complete Event
+ 3, // 0x06 - HCI_Authentication_Complete Event
+ 255, // 0x07 - HCI_Remote_Name_Request_Complete Event
+ 4, // 0x08 - HCI_Encryption_Change Event
+ 3, // 0x09 - HCI_Change_Connection_Link_Key_Complete Event
+ 4, // 0x0A - HCI_Master_Link_Key_Complete Event
+ 11, // 0x0B - HCI_Read_Remote_Supported_Features_Complete Event
+ 8, // 0x0C - HCI_Read_Remote_Version_Information_Complete Event
+ 21, // 0x0D - HCI_QoS_Setup_Complete Event
+ 3, // 0x0E - HCI_Command_Complete Event (Depends on command)
+ 4, // 0x0F - HCI_Command_Status Event
+ 1, // 0x10 - HCI_Hardware_Error Event
+ 2, // 0x11 - HCI_Flush_Occurred Event
+ 8, // 0x12 - HCI_Role_Change Event
+ 5, // 0x13 - HCI_Number_Of_Completed_Packets Event (Num_Handles = 1)
+ 6, // 0x14 - HCI_Mode_Change Event
+ 23, // 0x15 - HCI_Return_Link_Keys Event (Num_Keys = 1)
+ 6, // 0x16 - HCI_PIN_Code_Request Event
+ 6, // 0x17 - HCI_Link_Key_Request Event
+ 23, // 0x18 - HCI_Link_Key_Notification Event
+ 3, // 0x19 - HCI_Loopback_Command Event (Depends on command)
+ 1, // 0x1A - HCI_Data_Buffer_Overflow Event
+ 3, // 0x1B - HCI_Max_Slots_Change Event
+ 5, // 0x1C - HCI_Read_Clock_Offset_Complete Event
+ 5, // 0x1D - HCI_Connection_Packet_Type_Changed Event
+ 2, // 0x1E - HCI_QoS_Violation Event
+ 7, // 0x1F - HCI_Page_Scan_Mode_Change Event (Deprecated)
+ 7, // 0x20 - HCI_Page_Scan_Repetition_Mode_Change Event
+ 22, // 0x21 - HCI_Flow_Specification_Complet Event
+ 15, // 0x22 - HCI_Inquiry_Result_with_RSSI Event (Num_Responses = 1)
+ 13, // 0x23 - HCI_Read_Remote_Extended_Features_Complete Event
+ 0, // 0x24 - N/A
+ 0, // 0x25 - N/A
+ 0, // 0x26 - N/A
+ 0, // 0x27 - N/A
+ 0, // 0x28 - N/A
+ 0, // 0x29 - N/A
+ 0, // 0x2A - N/A
+ 0, // 0x2B - N/A
+ 17, // 0x2C - HCI_Synchronous_Connection_Complete Event
+ 9, // 0x2D - HCI_Synchronous_Connection_Changed Event
+ 11, // 0x2E - HCI_Sniff_Subrating Event
+ 255, // 0x2F - HCI_Extended_Inquiry_Result Event
+ 3, // 0x30 - HCI_Encryption_Key_Refresh_Complete Event
+ 6, // 0x31 - HCI_IO_Capability_Request Event
+ 9, // 0x32 - HCI_IO_Capability_Response Event
+ 10, // 0x33 - HCI_User_Confirmation_Request Event
+ 6, // 0x34 - HCI_User_Passkey_Request Event
+ 6, // 0x35 - HCI_Remote_OOB_Data_Request Event
+ 7, // 0x36 - HCI_Simple_Pairing_Complete Event
+ 0, // 0x37 - N/A
+ 4, // 0x38 - HCI_Link_Supervision_Timeout_Changed Event
+ 2, // 0x39 - HCI_Enhanced_Flush_Complete Event
+ 0, // 0x3A - N/A
+ 10, // 0x3B - HCI_User_Passkey_Notification Event
+ 7, // 0x3C - HCI_Keypress_Notification Event
+ 14, // 0x3D - HCI_Remote_Host_Supported_Features_Notification Event
+ 0, // 0x3E - LE Meta event
+ 0, // 0x3F - N/A
+ 2, // 0x40 - HCI_Physical_Link_Complete Event
+ 1, // 0x41 - HCI_Channel_Selected Event
+ 3, // 0x42 - HCI_Disconnection_Physical_Link_Complete Event
+ 2, // 0x43 - HCI_Physical_Link_Loss_Early_Warning Event
+ 1, // 0x44 - HCI_Physical_Link_Recovery Event
+ 5, // 0x45 - HCI_Logical_Link_Complete Event
+ 4, // 0x46 - HCI_Disconnection_Logical_Link_Complete Event
+ 3, // 0x47 - HCI_Flow_Spec_Modify_Complete Event
+ 9, // 0x48 - HCI_Number_Of_Completed_Data_Blocks Event (Num_Handles = 1)
+ 2, // 0x49 - HCI_AMP_Start_Test Event
+ 2, // 0x4A - HCI_AMP_Test_End Event
+ 18, // 0x4B - HCI_AMP_Receiver_Report Event
+ 3, // 0x4C - HCI_Short_Range_Mode_Change_Complete Event
+ 2, // 0x4D - HCI_AMP_Status_Change Event
+ 9, // 0x4E - HCI_Triggered_Clock_Capture Event
+ 1, // 0x4F - HCI_Synchronization_Train_Complete Event
+ 29, // 0x50 - HCI_Synchronization_Train_Received Event
+ 18, // 0x51 - HCI_Connectionless_Slave_Broadcast_Receive Event
+ // (Data_Length = 0)
+ 7, // 0x52 - HCI_Connectionless_Slave_Broadcast_Timeout Event
+ 7, // 0x53 - HCI_Truncated_Page_Complete Event
+ 0, // 0x54 - HCI_Slave_Page_Response_Timeout Event
+ 10, // 0x55 - HCI_Connectionless_Slave_Broadcast_Channel_Map_Change Event
+ 4, // 0x56 - HCI_Inquiry_Response_Notification Event
+ 2, // 0x57 - HCI_Authenticated_Payload_Timeout_Expired Event
+ 8, // 0x58 - HCI_SAM_Status_Change Event
+ 0, // 0x59 - N/A
+ 0, // 0x5A - N/A
+ 0, // 0x5B - N/A
+ 0, // 0x5C - N/A
+ 0, // 0x5D - N/A
+ 0, // 0x5E - N/A
+ 0, // 0x5F - N/A
+ 0, // 0x60 - N/A
+ 0, // 0x61 - N/A
+ 0, // 0x62 - N/A
+ 0, // 0x63 - N/A
+ 0, // 0x64 - N/A
+ 0, // 0x65 - N/A
+ 0, // 0x66 - N/A
+ 0, // 0x67 - N/A
+ 0, // 0x68 - N/A
+ 0, // 0x69 - N/A
+ 0, // 0x6A - N/A
+ 0, // 0x6B - N/A
+ 0, // 0x6C - N/A
+ 0, // 0x6D - N/A
+ 0, // 0x6E - N/A
+ 0, // 0x6F - N/A
+ 0, // 0x70 - N/A
+ 0, // 0x71 - N/A
+ 0, // 0x72 - N/A
+ 0, // 0x73 - N/A
+ 0, // 0x74 - N/A
+ 0, // 0x75 - N/A
+ 0, // 0x76 - N/A
+ 0, // 0x77 - N/A
+ 0, // 0x78 - N/A
+ 0, // 0x79 - N/A
+ 0, // 0x7A - N/A
+ 0, // 0x7B - N/A
+ 0, // 0x7C - N/A
+ 0, // 0x7D - N/A
+ 0, // 0x7E - N/A
+ 0, // 0x7F - N/A
+ 0, // 0x80 - N/A
+ 0, // 0x81 - N/A
+ 0, // 0x82 - N/A
+ 0, // 0x83 - N/A
+ 0, // 0x84 - N/A
+ 0, // 0x85 - N/A
+ 0, // 0x86 - N/A
+ 0, // 0x87 - N/A
+ 0, // 0x88 - N/A
+ 0, // 0x89 - N/A
+ 0, // 0x8A - N/A
+ 0, // 0x8B - N/A
+ 0, // 0x8C - N/A
+ 0, // 0x8D - N/A
+ 0, // 0x8E - N/A
+ 0, // 0x8F - N/A
+ 0, // 0x90 - N/A
+ 0, // 0x91 - N/A
+ 0, // 0x92 - N/A
+ 0, // 0x93 - N/A
+ 0, // 0x94 - N/A
+ 0, // 0x95 - N/A
+ 0, // 0x96 - N/A
+ 0, // 0x97 - N/A
+ 0, // 0x98 - N/A
+ 0, // 0x99 - N/A
+ 0, // 0x9A - N/A
+ 0, // 0x9B - N/A
+ 0, // 0x9C - N/A
+ 0, // 0x9D - N/A
+ 0, // 0x9E - N/A
+ 0, // 0x9F - N/A
+ 0, // 0xA0 - N/A
+ 0, // 0xA1 - N/A
+ 0, // 0xA2 - N/A
+ 0, // 0xA3 - N/A
+ 0, // 0xA4 - N/A
+ 0, // 0xA5 - N/A
+ 0, // 0xA6 - N/A
+ 0, // 0xA7 - N/A
+ 0, // 0xA8 - N/A
+ 0, // 0xA9 - N/A
+ 0, // 0xAA - N/A
+ 0, // 0xAB - N/A
+ 0, // 0xAC - N/A
+ 0, // 0xAD - N/A
+ 0, // 0xAE - N/A
+ 0, // 0xAF - N/A
+ 0, // 0xB0 - N/A
+ 0, // 0xB1 - N/A
+ 0, // 0xB2 - N/A
+ 0, // 0xB3 - N/A
+ 0, // 0xB4 - N/A
+ 0, // 0xB5 - N/A
+ 0, // 0xB6 - N/A
+ 0, // 0xB7 - N/A
+ 0, // 0xB8 - N/A
+ 0, // 0xB9 - N/A
+ 0, // 0xBA - N/A
+ 0, // 0xBB - N/A
+ 0, // 0xBC - N/A
+ 0, // 0xBD - N/A
+ 0, // 0xBE - N/A
+ 0, // 0xBF - N/A
+ 0, // 0xC0 - N/A
+ 0, // 0xC1 - N/A
+ 0, // 0xC2 - N/A
+ 0, // 0xC3 - N/A
+ 0, // 0xC4 - N/A
+ 0, // 0xC5 - N/A
+ 0, // 0xC6 - N/A
+ 0, // 0xC7 - N/A
+ 0, // 0xC8 - N/A
+ 0, // 0xC9 - N/A
+ 0, // 0xCA - N/A
+ 0, // 0xCB - N/A
+ 0, // 0xCC - N/A
+ 0, // 0xCD - N/A
+ 0, // 0xCE - N/A
+ 0, // 0xCF - N/A
+ 0, // 0xD0 - N/A
+ 0, // 0xD1 - N/A
+ 0, // 0xD2 - N/A
+ 0, // 0xD3 - N/A
+ 0, // 0xD4 - N/A
+ 0, // 0xD5 - N/A
+ 0, // 0xD6 - N/A
+ 0, // 0xD7 - N/A
+ 0, // 0xD8 - N/A
+ 0, // 0xD9 - N/A
+ 0, // 0xDA - N/A
+ 0, // 0xDB - N/A
+ 0, // 0xDC - N/A
+ 0, // 0xDD - N/A
+ 0, // 0xDE - N/A
+ 0, // 0xDF - N/A
+ 0, // 0xE0 - N/A
+ 0, // 0xE1 - N/A
+ 0, // 0xE2 - N/A
+ 0, // 0xE3 - N/A
+ 0, // 0xE4 - N/A
+ 0, // 0xE5 - N/A
+ 0, // 0xE6 - N/A
+ 0, // 0xE7 - N/A
+ 0, // 0xE8 - N/A
+ 0, // 0xE9 - N/A
+ 0, // 0xEA - N/A
+ 0, // 0xEB - N/A
+ 0, // 0xEC - N/A
+ 0, // 0xED - N/A
+ 0, // 0xEE - N/A
+ 0, // 0xEF - N/A
+ 0, // 0xF0 - N/A
+ 0, // 0xF1 - N/A
+ 0, // 0xF2 - N/A
+ 0, // 0xF3 - N/A
+ 0, // 0xF4 - N/A
+ 0, // 0xF5 - N/A
+ 0, // 0xF6 - N/A
+ 0, // 0xF7 - N/A
+ 0, // 0xF8 - N/A
+ 0, // 0xF9 - N/A
+ 0, // 0xFA - N/A
+ 0, // 0xFB - N/A
+ 0, // 0xFC - N/A
+ 0, // 0xFD - N/A
+ 0, // 0xFE - N/A
+ 0, // 0xFF - HCI_Vendor_Specific Event
+};
diff --git a/stack/test/stack_avrcp_test.cc b/stack/test/stack_avrcp_test.cc
new file mode 100644
index 000000000..ad1cc9e72
--- /dev/null
+++ b/stack/test/stack_avrcp_test.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2020 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 <dlfcn.h>
+#include <gtest/gtest.h>
+
+#include "stack/include/avrc_api.h"
+
+class StackAvrcpTest : public ::testing::Test {
+ protected:
+ StackAvrcpTest() = default;
+
+ virtual ~StackAvrcpTest() = default;
+};
+
+TEST_F(StackAvrcpTest, test_avrcp_parse_browse_cmd) {
+ uint8_t scratch_buf[512]{};
+ tAVRC_MSG msg{};
+ tAVRC_COMMAND result{};
+ uint8_t browse_cmd_buf[512]{};
+
+ msg.hdr.opcode = AVRC_OP_BROWSE;
+ msg.browse.p_browse_data = browse_cmd_buf;
+ msg.browse.browse_len = 2;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_SET_BROWSED_PLAYER;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 5;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_FOLDER_ITEMS;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 13;
+ uint8_t* p = &browse_cmd_buf[3];
+ UINT8_TO_STREAM(p, AVRC_SCOPE_NOW_PLAYING); // scope
+ UINT32_TO_STREAM(p, 0x00000001); // start_item
+ UINT32_TO_STREAM(p, 0x00000002); // end_item
+ browse_cmd_buf[12] = 0; // attr_count
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_CHANGE_PATH;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 14;
+ p = &browse_cmd_buf[3];
+ UINT16_TO_STREAM(p, 0x1234); // uid_counter
+ UINT8_TO_STREAM(p, AVRC_DIR_UP); // direction
+ UINT8_TO_STREAM(p, 0); // attr_count
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_ITEM_ATTRIBUTES;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 15;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_GET_TOTAL_NUM_OF_ITEMS;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ msg.browse.browse_len = 4;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+
+ memset(browse_cmd_buf, 0, sizeof(browse_cmd_buf));
+ browse_cmd_buf[0] = AVRC_PDU_SEARCH;
+ msg.browse.browse_len = 3;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_BAD_CMD);
+
+ p = &browse_cmd_buf[3];
+ UINT16_TO_STREAM(p, 0x0000); // charset_id
+ UINT16_TO_STREAM(p, 0x0000); // str_len
+ msg.browse.browse_len = 7;
+ EXPECT_EQ(AVRC_ParsCommand(&msg, &result, scratch_buf, sizeof(scratch_buf)),
+ AVRC_STS_NO_ERROR);
+}