diff options
| -rw-r--r-- | TEST_MAPPING | 4 | ||||
| -rw-r--r-- | binder/android/bluetooth/IBluetoothManager.aidl | 2 | ||||
| -rw-r--r-- | bta/av/bta_av_aact.cc | 3 | ||||
| -rw-r--r-- | bta/av/bta_av_ssm.cc | 2 | ||||
| -rw-r--r-- | bta/hf_client/bta_hf_client_rfc.cc | 5 | ||||
| -rw-r--r-- | btif/Android.bp | 33 | ||||
| -rw-r--r-- | btif/src/btif_a2dp_sink.cc | 1 | ||||
| -rw-r--r-- | btif/src/btif_rc.cc | 33 | ||||
| -rw-r--r-- | btif/test/btif_rc_test.cc | 131 | ||||
| -rw-r--r-- | internal_include/bt_target.h | 2 | ||||
| -rw-r--r-- | profile/avrcp/device.cc | 23 | ||||
| -rw-r--r-- | stack/Android.bp | 1 | ||||
| -rw-r--r-- | stack/BUILD.gn | 1 | ||||
| -rw-r--r-- | stack/avdt/avdt_msg.cc | 30 | ||||
| -rw-r--r-- | stack/avrc/avrc_pars_ct.cc | 2 | ||||
| -rw-r--r-- | stack/avrc/avrc_pars_tg.cc | 52 | ||||
| -rw-r--r-- | stack/btm/btm_ble_multi_adv.cc | 15 | ||||
| -rw-r--r-- | stack/btm/btm_inq.cc | 21 | ||||
| -rw-r--r-- | stack/btm/btm_int.h | 2 | ||||
| -rw-r--r-- | stack/btu/btu_hcif.cc | 8 | ||||
| -rw-r--r-- | stack/crypto_toolbox/aes_cmac.cc | 3 | ||||
| -rw-r--r-- | stack/include/hci_evt_length.h | 278 | ||||
| -rw-r--r-- | stack/test/stack_avrcp_test.cc | 112 |
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); +} |
