1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
16
17 #include <pw_bluetooth/hci_android.emb.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
20
21 namespace bt::hci {
22
23 namespace android_hci = hci_spec::vendor::android;
24 namespace android_emb = pw::bluetooth::vendor::android_hci;
25
CommandPacket(hci_spec::OpCode opcode,size_t packet_size)26 CommandPacket::CommandPacket(hci_spec::OpCode opcode, size_t packet_size)
27 : DynamicPacket(packet_size) {
28 PW_CHECK(packet_size >=
29 pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes(),
30 "command packet size must be at least 3 bytes to accomodate header");
31 auto header = view<pw::bluetooth::emboss::CommandHeaderWriter>();
32 header.opcode_bits().BackingStorage().WriteUInt(opcode);
33 header.parameter_total_size().Write(
34 packet_size -
35 pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes());
36 }
37
opcode() const38 hci_spec::OpCode CommandPacket::opcode() const {
39 return header_view().opcode_bits().BackingStorage().ReadUInt();
40 }
41
ogf() const42 uint8_t CommandPacket::ogf() const {
43 return header_view().opcode_bits().ogf().Read();
44 }
45
ocf() const46 uint16_t CommandPacket::ocf() const {
47 return header_view().opcode_bits().ocf().Read();
48 }
49
header_view() const50 pw::bluetooth::emboss::CommandHeaderView CommandPacket::header_view() const {
51 return view<pw::bluetooth::emboss::CommandHeaderView>();
52 }
53
EventPacket(size_t packet_size)54 EventPacket::EventPacket(size_t packet_size) : DynamicPacket(packet_size) {
55 PW_CHECK(
56 packet_size >= pw::bluetooth::emboss::EventHeader::IntrinsicSizeInBytes(),
57 "event packet size must be at least 2 bytes to accomodate header");
58 }
59
event_code() const60 hci_spec::EventCode EventPacket::event_code() const {
61 return view<pw::bluetooth::emboss::EventHeaderView>()
62 .event_code_uint()
63 .Read();
64 }
65
StatusCode() const66 std::optional<pw::bluetooth::emboss::StatusCode> EventPacket::StatusCode()
67 const {
68 switch (event_code()) {
69 case hci_spec::kAuthenticationCompleteEventCode:
70 return StatusCodeFromView<
71 pw::bluetooth::emboss::AuthenticationCompleteEventView>();
72 case hci_spec::kChangeConnectionLinkKeyCompleteEventCode:
73 return StatusCodeFromView<
74 pw::bluetooth::emboss::ChangeConnectionLinkKeyCompleteEventView>();
75 case hci_spec::kCommandCompleteEventCode:
76 return StatusCodeFromView<
77 pw::bluetooth::emboss::SimpleCommandCompleteEventView>();
78 case hci_spec::kCommandStatusEventCode:
79 return StatusCodeFromView<
80 pw::bluetooth::emboss::CommandStatusEventView>();
81 case hci_spec::kConnectionCompleteEventCode:
82 return StatusCodeFromView<
83 pw::bluetooth::emboss::ConnectionCompleteEventView>();
84 case hci_spec::kDisconnectionCompleteEventCode:
85 return StatusCodeFromView<
86 pw::bluetooth::emboss::DisconnectionCompleteEventView>();
87 case hci_spec::kEncryptionChangeEventCode:
88 return StatusCodeFromView<
89 pw::bluetooth::emboss::EncryptionChangeEventV1View>();
90 case hci_spec::kEncryptionKeyRefreshCompleteEventCode:
91 return StatusCodeFromView<
92 pw::bluetooth::emboss::EncryptionKeyRefreshCompleteEventView>();
93 case hci_spec::kInquiryCompleteEventCode:
94 return StatusCodeFromView<
95 pw::bluetooth::emboss::InquiryCompleteEventView>();
96 case hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode:
97 return StatusCodeFromView<
98 pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventView>();
99 case hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode:
100 return StatusCodeFromView<
101 pw::bluetooth::emboss::
102 ReadRemoteSupportedFeaturesCompleteEventView>();
103 case hci_spec::kReadRemoteVersionInfoCompleteEventCode:
104 return StatusCodeFromView<
105 pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventView>();
106 case hci_spec::kRemoteNameRequestCompleteEventCode: {
107 // Tests expect that a kPacketMalformed status is returned for incomplete
108 // events, even if they contain the status field.
109 pw::bluetooth::emboss::RemoteNameRequestCompleteEventView event_view(
110 data().data(), size());
111 if (!event_view.IsComplete()) {
112 return std::nullopt;
113 }
114 return event_view.status().UncheckedRead();
115 }
116 case hci_spec::kRoleChangeEventCode:
117 return StatusCodeFromView<pw::bluetooth::emboss::RoleChangeEventView>();
118 case hci_spec::kSimplePairingCompleteEventCode:
119 return StatusCodeFromView<
120 pw::bluetooth::emboss::SimplePairingCompleteEventView>();
121 case hci_spec::kSynchronousConnectionCompleteEventCode:
122 return StatusCodeFromView<
123 pw::bluetooth::emboss::SynchronousConnectionCompleteEventView>();
124 case hci_spec::kVendorDebugEventCode: {
125 hci_spec::EventCode subevent_code =
126 view<pw::bluetooth::emboss::VendorDebugEventView>()
127 .subevent_code()
128 .Read();
129
130 switch (subevent_code) {
131 case android_hci::kLEMultiAdvtStateChangeSubeventCode: {
132 return StatusCodeFromView<
133 android_emb::LEMultiAdvtStateChangeSubeventView>();
134 }
135
136 default: {
137 BT_PANIC("Emboss vendor subevent (%#.2x) not implemented",
138 subevent_code);
139 break;
140 }
141 }
142
143 break;
144 }
145
146 case hci_spec::kLEMetaEventCode: {
147 hci_spec::EventCode subevent_code =
148 view<pw::bluetooth::emboss::LEMetaEventView>().subevent_code().Read();
149
150 switch (subevent_code) {
151 case hci_spec::kLECISEstablishedSubeventCode: {
152 return StatusCodeFromView<
153 pw::bluetooth::emboss::LECISEstablishedSubeventView>();
154 }
155 case hci_spec::kLEConnectionCompleteSubeventCode: {
156 return StatusCodeFromView<
157 pw::bluetooth::emboss::LEConnectionCompleteSubeventView>();
158 }
159 case hci_spec::kLEConnectionUpdateCompleteSubeventCode: {
160 return StatusCodeFromView<
161 pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventView>();
162 }
163 case hci_spec::kLEEnhancedConnectionCompleteSubeventCode: {
164 return StatusCodeFromView<
165 pw::bluetooth::emboss::
166 LEEnhancedConnectionCompleteSubeventV1View>();
167 }
168 case hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode: {
169 return StatusCodeFromView<
170 pw::bluetooth::emboss::
171 LEReadRemoteFeaturesCompleteSubeventView>();
172 }
173 case hci_spec::kLERequestPeerSCACompleteSubeventCode: {
174 return StatusCodeFromView<
175 pw::bluetooth::emboss::LERequestPeerSCACompleteSubeventView>();
176 }
177 case hci_spec::kLEAdvertisingSetTerminatedSubeventCode: {
178 return StatusCodeFromView<
179 pw::bluetooth::emboss::LEAdvertisingSetTerminatedSubeventView>();
180 }
181 default: {
182 BT_PANIC("Emboss LE meta subevent (%#.2x) not implemented",
183 subevent_code);
184 break;
185 }
186 }
187
188 break;
189 }
190
191 default: {
192 BT_PANIC("Emboss event (%#.2x) not implemented", event_code());
193 break;
194 }
195 }
196
197 return std::nullopt;
198 }
199
ToResult() const200 hci::Result<> EventPacket::ToResult() const {
201 std::optional<pw::bluetooth::emboss::StatusCode> maybe_status_code =
202 StatusCode();
203 if (!maybe_status_code.has_value()) {
204 return bt::ToResult(HostError::kPacketMalformed);
205 }
206 return bt::ToResult(*maybe_status_code);
207 }
208
209 } // namespace bt::hci
210