1 /*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "vendor_packet.h"
18
19 namespace bluetooth {
20 namespace avrcp {
21
MakeBuilder(CType ctype,CommandPdu pdu,PacketType packet_type,std::unique_ptr<::bluetooth::PacketBuilder> payload)22 std::unique_ptr<VendorPacketBuilder> VendorPacketBuilder::MakeBuilder(
23 CType ctype, CommandPdu pdu, PacketType packet_type,
24 std::unique_ptr<::bluetooth::PacketBuilder> payload) {
25 // If the payload size is greater than max uint16_t
26 // the packet should be fragmented
27 CHECK_LE(payload->size(), size_t(0xFFFF))
28 << __func__ << ": payload size bigger than uint16_t";
29
30 std::unique_ptr<VendorPacketBuilder> builder(
31 new VendorPacketBuilder(ctype, pdu, packet_type));
32 builder->payload_ = std::move(payload);
33
34 return builder;
35 }
36
size() const37 size_t VendorPacketBuilder::size() const {
38 return VendorPacket::kMinSize() + payload_->size();
39 }
40
Serialize(const std::shared_ptr<::bluetooth::Packet> & pkt)41 bool VendorPacketBuilder::Serialize(
42 const std::shared_ptr<::bluetooth::Packet>& pkt) {
43 ReserveSpace(pkt, size());
44
45 // Push the standard avrcp headers
46 PacketBuilder::PushHeader(pkt);
47
48 // Push the avrcp vendor command headers
49 CHECK_LT(payload_->size(), size_t(0xFFFF))
50 << __func__ << ": payload size bigger than uint16_t";
51 PushHeader(pkt, payload_->size());
52
53 // Push the payload for the packet
54 return payload_->Serialize(pkt);
55 }
56
PushHeader(const std::shared_ptr<::bluetooth::Packet> & pkt,uint16_t parameter_length)57 void VendorPacketBuilder::PushHeader(
58 const std::shared_ptr<::bluetooth::Packet>& pkt,
59 uint16_t parameter_length) {
60 PushCompanyId(pkt, BLUETOOTH_COMPANY_ID);
61 AddPayloadOctets1(pkt, static_cast<uint8_t>(pdu_));
62 AddPayloadOctets1(pkt, static_cast<uint8_t>(packet_type_));
63 AddPayloadOctets2(pkt, base::ByteSwap(parameter_length));
64 }
65
PushAttributeValue(const std::shared_ptr<::bluetooth::Packet> & pkt,const AttributeEntry & entry)66 bool VendorPacketBuilder::PushAttributeValue(
67 const std::shared_ptr<::bluetooth::Packet>& pkt,
68 const AttributeEntry& entry) {
69 AddPayloadOctets4(pkt,
70 base::ByteSwap(static_cast<uint32_t>(entry.attribute())));
71 uint16_t character_set = 0x006a; // UTF-8
72 AddPayloadOctets2(pkt, base::ByteSwap(character_set));
73 uint16_t value_length = entry.value().length();
74 AddPayloadOctets2(pkt, base::ByteSwap(value_length));
75 for (int i = 0; i < value_length; i++) {
76 AddPayloadOctets1(pkt, entry.value()[i]);
77 }
78
79 return true;
80 }
81
GetCompanyId() const82 uint32_t VendorPacket::GetCompanyId() const {
83 return PullCompanyId(begin() + Packet::kMinSize());
84 }
85
GetCommandPdu() const86 CommandPdu VendorPacket::GetCommandPdu() const {
87 auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(3));
88 return static_cast<CommandPdu>(value);
89 }
90
GetPacketType() const91 PacketType VendorPacket::GetPacketType() const {
92 auto value = *(begin() + Packet::kMinSize() + static_cast<size_t>(4));
93 return static_cast<PacketType>(value);
94 }
95
GetParameterLength() const96 uint16_t VendorPacket::GetParameterLength() const {
97 auto it = begin() + Packet::kMinSize() + static_cast<size_t>(5);
98 // Swap to little endian
99 return it.extractBE<uint16_t>();
100 }
101
IsValid() const102 bool VendorPacket::IsValid() const {
103 if (size() < VendorPacket::kMinSize()) return false;
104
105 auto start = begin() + VendorPacket::kMinSize();
106 // Even if end is less than start and a sign extension occurs, thats fine as
107 // its pretty definitive proof that the packet is poorly formated
108 return GetParameterLength() == (end() - start);
109 }
110
ToString() const111 std::string VendorPacket::ToString() const {
112 std::stringstream ss;
113 ss << "VendorPacket: " << std::endl;
114 ss << " └ cType = " << GetCType() << std::endl;
115 ss << " └ Subunit Type = " << loghex(GetSubunitType()) << std::endl;
116 ss << " └ Subunit ID = " << loghex(GetSubunitId()) << std::endl;
117 ss << " └ OpCode = " << GetOpcode() << std::endl;
118 ss << " └ Company ID = " << loghex(GetCompanyId()) << std::endl;
119 ss << " └ Command PDU = " << GetCommandPdu() << std::endl;
120 ss << " └ PacketType = " << GetPacketType() << std::endl;
121 ss << " └ Parameter Length = " << loghex(GetParameterLength()) << std::endl;
122 ss << " └ Payload =";
123 for (auto it = begin(); it != end(); it++) {
124 ss << " " << loghex(*it);
125 }
126 ss << std::endl;
127 return ss.str();
128 }
129
130 } // namespace avrcp
131 } // namespace bluetooth
132