namespace bluetooth {
namespace avrcp {
-std::unique_ptr<GeneralRejectBuilder> GeneralRejectBuilder::MakeBuilder(
- BrowsePdu pdu, Status reason) {
+std::unique_ptr<GeneralRejectBuilder> GeneralRejectBuilder::MakeBuilder(Status reason) {
std::unique_ptr<GeneralRejectBuilder> builder =
- std::unique_ptr<GeneralRejectBuilder>(
- new GeneralRejectBuilder(pdu, reason));
+ std::unique_ptr<GeneralRejectBuilder>(new GeneralRejectBuilder(reason));
return builder;
}
public:
virtual ~GeneralRejectBuilder() = default;
- static std::unique_ptr<GeneralRejectBuilder> MakeBuilder(BrowsePdu pdu,
- Status reason);
+ static std::unique_ptr<GeneralRejectBuilder> MakeBuilder(Status reason);
virtual size_t size() const override;
virtual bool Serialize(
protected:
Status reason_;
- GeneralRejectBuilder(BrowsePdu pdu, Status reason)
- : BrowsePacketBuilder(pdu), reason_(reason){};
+ GeneralRejectBuilder(Status reason) : BrowsePacketBuilder(BrowsePdu::GENERAL_REJECT), reason_(reason){};
};
} // namespace avrcp
bool RegisterNotificationResponse::IsValid() const {
if (!VendorPacket::IsValid()) return false;
if (size() < kMinSize()) return false;
- if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED)
+ if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED && GetCType() != CType::REJECTED) {
return false;
+ }
switch (GetEvent()) {
case Event::VOLUME_CHANGED:
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};
+std::vector<uint8_t> register_notification_invalid = {0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31,
+ 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
// AVRCP Interim Playback Status Notification
std::vector<uint8_t> interim_play_status_notification = {
// start_item = 0x00
// end_item = 0x05
// attributes_requested: All Items
-std::vector<uint8_t> get_folder_items_request_now_playing = {
- 0x71, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x05, 0x00};
+std::vector<uint8_t> get_folder_items_request_now_playing = {0x71, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00};
// AVRCP Browse Get Folder Items Response packet with range out of bounds error
std::vector<uint8_t> get_folder_items_error_response = {0x71, 0x00, 0x01, 0x0b};
std::vector<uint8_t> set_absolute_volume_response = {
0x09, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x43};
+// Invalid Packets
+// Short Vendor Packet
+std::vector<uint8_t> short_vendor_packet = {0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01};
+
+// Short Get Capabilities Request Packet
+std::vector<uint8_t> short_get_capabilities_request = {0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x00};
+
+// Short Get Element Attributes Request Packet
+std::vector<uint8_t> short_get_element_attributes_request = {0x01, 0x48, 0x00, 0x00, 0x19,
+ 0x58, 0x20, 0x00, 0x00, 0x00};
+
+// Short Play Item Request Packet
+std::vector<uint8_t> short_play_item_request = {0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x74, 0x00, 0x00, 0x00};
+
+// Short Set Addressed Player Request Packet
+std::vector<uint8_t> short_set_addressed_player_request = {0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x00};
+
+// Short Browse Packet
+std::vector<uint8_t> short_browse_packet = {0x71, 0x00, 0x0a};
+
+// Short Get Folder Items Request Packet
+std::vector<uint8_t> short_get_folder_items_request = {0x71, 0x00, 0x00};
+
+// Short Get Total Number of Items Request Packet
+std::vector<uint8_t> short_get_total_number_of_items_request = {0x75, 0x00, 0x00};
+
+// Short Change Path Request Packet
+std::vector<uint8_t> short_change_path_request = {0x72, 0x00, 0x00};
+
+// Short Get Item Attributes Request Packet
+std::vector<uint8_t> short_get_item_attributes_request = {0x73, 0x00, 0x00};
+
} // namespace
using TestGeneralRejectPacket = TestPacketType<BrowsePacket>;
TEST(GeneralRejectPacketBuilderTest, buildPacketTest) {
- auto builder = GeneralRejectBuilder::MakeBuilder(BrowsePdu::GENERAL_REJECT,
- Status::INVALID_COMMAND);
+ auto builder = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
ASSERT_EQ(builder->size(), general_reject_invalid_command_packet.size());
CHECK(media_interface_);
DEVICE_VLOG(3) << __func__ << ": pdu=" << pkt->GetCommandPdu();
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+ send_message(label, false, std::move(response));
+ return;
+ }
+
// All CTypes at and above NOT_IMPLEMENTED are all response types.
if (pkt->GetCType() == CType::NOT_IMPLEMENTED) {
return;
} break;
case CommandPdu::GET_ELEMENT_ATTRIBUTES: {
- media_interface_->GetSongInfo(base::Bind(
- &Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
- label, Packet::Specialize<GetElementAttributesRequest>(pkt)));
+ auto get_element_attributes_request_pkt = Packet::Specialize<GetElementAttributesRequest>(pkt);
+
+ if (!get_element_attributes_request_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));
+ }
+ media_interface_->GetSongInfo(base::Bind(&Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
+ label, get_element_attributes_request_pkt));
} break;
case CommandPdu::GET_PLAY_STATUS: {
// 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.
- media_interface_->GetMediaPlayerList(base::Bind(
- &Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
- label, Packet::Specialize<SetAddressedPlayerRequest>(pkt)));
+ auto set_addressed_player_request = Packet::Specialize<SetAddressedPlayerRequest>(pkt);
+
+ if (!set_addressed_player_request->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));
+ return;
+ }
+
+ media_interface_->GetMediaPlayerList(base::Bind(&Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
+ label, set_addressed_player_request));
} break;
default: {
DEVICE_VLOG(4) << __func__
<< ": capability=" << pkt->GetCapabilityRequested();
+ 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));
+ return;
+ }
+
switch (pkt->GetCapabilityRequested()) {
case Capability::COMPANY_ID: {
auto response =
void Device::HandleNotification(
uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt) {
if (!pkt->IsValid()) {
- DEVICE_LOG(ERROR) << __func__ << ": Request packet is not valid";
+ 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));
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) {
uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
SongInfo info) {
DEVICE_VLOG(2) << __func__;
+
auto get_element_attributes_pkt = pkt;
auto attributes_requested =
get_element_attributes_pkt->GetAttributesRequested();
}
void Device::MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt) {
- DEVICE_VLOG(4) << __func__ << ": opcode=" << pkt->GetOpcode();
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+ send_message(label, false, std::move(response));
+ return;
+ }
+ DEVICE_VLOG(4) << __func__ << ": opcode=" << pkt->GetOpcode();
active_labels_.insert(label);
-
switch (pkt->GetOpcode()) {
// TODO (apanicke): Remove handling of UNIT_INFO and SUBUNIT_INFO from
// the AVRC_API and instead handle it here to reduce fragmentation.
} break;
case Opcode::PASS_THROUGH: {
auto pass_through_packet = Packet::Specialize<PassThroughPacket>(pkt);
+
+ if (!pass_through_packet->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+ send_message(label, false, std::move(response));
+ return;
+ }
+
auto response = PassThroughPacketBuilder::MakeBuilder(
true, pass_through_packet->GetKeyState() == KeyState::PUSHED,
pass_through_packet->GetOperationId());
DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
<< " uid=" << pkt->GetUid();
+ 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));
+ return;
+ }
+
std::string media_id = "";
switch (pkt->GetScope()) {
case Scope::NOW_PLAYING:
void Device::BrowseMessageReceived(uint8_t label,
std::shared_ptr<BrowsePacket> pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
+ send_message(label, false, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(1) << __func__ << ": pdu=" << pkt->GetPdu();
switch (pkt->GetPdu()) {
break;
default:
DEVICE_LOG(WARNING) << __func__ << ": " << pkt->GetPdu();
- auto response = GeneralRejectBuilder::MakeBuilder(
- BrowsePdu::GENERAL_REJECT, Status::INVALID_COMMAND);
+ auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
send_message(label, true, std::move(response));
break;
void Device::HandleGetFolderItems(uint8_t label,
std::shared_ptr<GetFolderItemsRequest> pkt) {
+ if (!pkt->IsValid()) {
+ // The specific get folder items builder is unimportant on failure.
+ DEVICE_LOG(WARNING) << __func__ << ": Get folder items request packet is not valid";
+ auto response =
+ GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, browse_mtu_);
+ send_message(label, true, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
switch (pkt->GetScope()) {
break;
default:
DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope();
+ auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0, browse_mtu_);
+ send_message(label, true, std::move(response));
break;
}
}
void Device::HandleGetTotalNumberOfItems(
uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0);
+ send_message(label, true, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
switch (pkt->GetScope()) {
void Device::HandleChangePath(uint8_t label,
std::shared_ptr<ChangePathRequest> pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
+ send_message(label, true, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(2) << __func__ << ": direction=" << pkt->GetDirection()
<< " uid=" << loghex(pkt->GetUid());
void Device::HandleGetItemAttributes(
uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, browse_mtu_);
+ send_message(label, true, std::move(builder));
+ return;
+ }
+
DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
<< " uid=" << loghex(pkt->GetUid())
<< " uid counter=" << loghex(pkt->GetUidCounter());
send_message(label, true, std::move(builder));
return;
}
+
switch (pkt->GetScope()) {
case Scope::NOW_PLAYING: {
media_interface_->GetNowPlayingList(
void Device::HandleSetBrowsedPlayer(
uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt) {
+ if (!pkt->IsValid()) {
+ DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+ auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0, 0, "");
+ send_message(label, true, std::move(response));
+ return;
+ }
+
DEVICE_VLOG(2) << __func__ << ": player_id=" << pkt->GetPlayerId();
media_interface_->SetBrowsedPlayer(
pkt->GetPlayerId(),
SendMessage(1, reg_notif_request);
}
+TEST_F(AvrcpDeviceTest, invalidVendorPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestAvrcpPacket::Make(short_vendor_packet);
+ SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidCapabilitiesPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestAvrcpPacket::Make(short_get_capabilities_request);
+ SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetElementAttributesPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_ELEMENT_ATTRIBUTES, Status::INVALID_PARAMETER);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestAvrcpPacket::Make(short_get_element_attributes_request);
+ SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidPlayItemPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM, Status::INVALID_PARAMETER);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestAvrcpPacket::Make(short_play_item_request);
+ SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidSetAddressedPlayerPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PARAMETER);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestAvrcpPacket::Make(short_set_addressed_player_request);
+ SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidBrowsePacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
+ EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestBrowsePacket::Make(short_browse_packet);
+ SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetFolderItemsPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
+ EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestBrowsePacket::Make(short_get_folder_items_request);
+ SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetTotalNumberOfItemsPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
+ EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestBrowsePacket::Make(short_get_total_number_of_items_request);
+ SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidChangePathPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
+ EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestBrowsePacket::Make(short_change_path_request);
+ SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetItemAttributesPacketTest) {
+ MockMediaInterface interface;
+ NiceMock<MockA2dpInterface> a2dp_interface;
+
+ test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+ auto rsp = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0xFFFF);
+ EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+ auto short_packet = TestBrowsePacket::Make(short_get_item_attributes_request);
+ SendBrowseMessage(1, short_packet);
+}
+
} // namespace avrcp
} // namespace bluetooth