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_assert/check.h>
18 #include <pw_bluetooth/hci_android.emb.h>
19
20 #include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
21
22 namespace bt::hci {
23
24 namespace android_hci = hci_spec::vendor::android;
25 namespace android_emb = pw::bluetooth::vendor::android_hci;
26
CommandPacket(hci_spec::OpCode opcode,size_t packet_size)27 CommandPacket::CommandPacket(hci_spec::OpCode opcode, size_t packet_size)
28 : DynamicPacket(packet_size) {
29 PW_CHECK(packet_size >=
30 pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes(),
31 "command packet size must be at least 3 bytes to accomodate header");
32 auto header = view<pw::bluetooth::emboss::CommandHeaderWriter>();
33 header.opcode_bits().BackingStorage().WriteUInt(opcode);
34 header.parameter_total_size().Write(
35 packet_size -
36 pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes());
37 }
38
opcode() const39 hci_spec::OpCode CommandPacket::opcode() const {
40 return header_view().opcode_bits().BackingStorage().ReadUInt();
41 }
42
ogf() const43 uint8_t CommandPacket::ogf() const {
44 return header_view().opcode_bits().ogf().Read();
45 }
46
ocf() const47 uint16_t CommandPacket::ocf() const {
48 return header_view().opcode_bits().ocf().Read();
49 }
50
header_view() const51 pw::bluetooth::emboss::CommandHeaderView CommandPacket::header_view() const {
52 return view<pw::bluetooth::emboss::CommandHeaderView>();
53 }
54
EventPacket(size_t packet_size)55 EventPacket::EventPacket(size_t packet_size) : DynamicPacket(packet_size) {
56 PW_CHECK(
57 packet_size >= pw::bluetooth::emboss::EventHeader::IntrinsicSizeInBytes(),
58 "event packet size must be at least 2 bytes to accomodate header");
59 }
60
event_code() const61 hci_spec::EventCode EventPacket::event_code() const {
62 return view<pw::bluetooth::emboss::EventHeaderView>()
63 .event_code_uint()
64 .Read();
65 }
66
StatusCode() const67 std::optional<pw::bluetooth::emboss::StatusCode> EventPacket::StatusCode()
68 const {
69 switch (event_code()) {
70 case hci_spec::kAuthenticationCompleteEventCode:
71 return StatusCodeFromView<
72 pw::bluetooth::emboss::AuthenticationCompleteEventView>();
73 case hci_spec::kChangeConnectionLinkKeyCompleteEventCode:
74 return StatusCodeFromView<
75 pw::bluetooth::emboss::ChangeConnectionLinkKeyCompleteEventView>();
76 case hci_spec::kCommandCompleteEventCode:
77 return StatusCodeFromView<
78 pw::bluetooth::emboss::SimpleCommandCompleteEventView>();
79 case hci_spec::kCommandStatusEventCode:
80 return StatusCodeFromView<
81 pw::bluetooth::emboss::CommandStatusEventView>();
82 case hci_spec::kConnectionCompleteEventCode:
83 return StatusCodeFromView<
84 pw::bluetooth::emboss::ConnectionCompleteEventView>();
85 case hci_spec::kDisconnectionCompleteEventCode:
86 return StatusCodeFromView<
87 pw::bluetooth::emboss::DisconnectionCompleteEventView>();
88 case hci_spec::kEncryptionChangeEventCode:
89 return StatusCodeFromView<
90 pw::bluetooth::emboss::EncryptionChangeEventV1View>();
91 case hci_spec::kEncryptionKeyRefreshCompleteEventCode:
92 return StatusCodeFromView<
93 pw::bluetooth::emboss::EncryptionKeyRefreshCompleteEventView>();
94 case hci_spec::kInquiryCompleteEventCode:
95 return StatusCodeFromView<
96 pw::bluetooth::emboss::InquiryCompleteEventView>();
97 case hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode:
98 return StatusCodeFromView<
99 pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventView>();
100 case hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode:
101 return StatusCodeFromView<
102 pw::bluetooth::emboss::
103 ReadRemoteSupportedFeaturesCompleteEventView>();
104 case hci_spec::kReadRemoteVersionInfoCompleteEventCode:
105 return StatusCodeFromView<
106 pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventView>();
107 case hci_spec::kRemoteNameRequestCompleteEventCode: {
108 // Tests expect that a kPacketMalformed status is returned for incomplete
109 // events, even if they contain the status field.
110 pw::bluetooth::emboss::RemoteNameRequestCompleteEventView event_view(
111 data().data(), size());
112 if (!event_view.IsComplete()) {
113 return std::nullopt;
114 }
115 return event_view.status().UncheckedRead();
116 }
117 case hci_spec::kRoleChangeEventCode:
118 return StatusCodeFromView<pw::bluetooth::emboss::RoleChangeEventView>();
119 case hci_spec::kSimplePairingCompleteEventCode:
120 return StatusCodeFromView<
121 pw::bluetooth::emboss::SimplePairingCompleteEventView>();
122 case hci_spec::kSynchronousConnectionCompleteEventCode:
123 return StatusCodeFromView<
124 pw::bluetooth::emboss::SynchronousConnectionCompleteEventView>();
125 case hci_spec::kVendorDebugEventCode: {
126 hci_spec::EventCode subevent_code =
127 view<pw::bluetooth::emboss::VendorDebugEventView>()
128 .subevent_code()
129 .Read();
130
131 switch (subevent_code) {
132 case android_hci::kLEMultiAdvtStateChangeSubeventCode: {
133 return StatusCodeFromView<
134 android_emb::LEMultiAdvtStateChangeSubeventView>();
135 }
136
137 default: {
138 PW_CRASH("Emboss vendor subevent (%#.2x) not implemented",
139 subevent_code);
140 break;
141 }
142 }
143
144 break;
145 }
146
147 case hci_spec::kLEMetaEventCode: {
148 hci_spec::EventCode subevent_code =
149 view<pw::bluetooth::emboss::LEMetaEventView>().subevent_code().Read();
150
151 switch (subevent_code) {
152 case hci_spec::kLECISEstablishedSubeventCode: {
153 return StatusCodeFromView<
154 pw::bluetooth::emboss::LECISEstablishedSubeventView>();
155 }
156 case hci_spec::kLEConnectionCompleteSubeventCode: {
157 return StatusCodeFromView<
158 pw::bluetooth::emboss::LEConnectionCompleteSubeventView>();
159 }
160 case hci_spec::kLEConnectionUpdateCompleteSubeventCode: {
161 return StatusCodeFromView<
162 pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventView>();
163 }
164 case hci_spec::kLEEnhancedConnectionCompleteSubeventCode: {
165 return StatusCodeFromView<
166 pw::bluetooth::emboss::
167 LEEnhancedConnectionCompleteSubeventV1View>();
168 }
169 case hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode: {
170 return StatusCodeFromView<
171 pw::bluetooth::emboss::
172 LEReadRemoteFeaturesCompleteSubeventView>();
173 }
174 case hci_spec::kLERequestPeerSCACompleteSubeventCode: {
175 return StatusCodeFromView<
176 pw::bluetooth::emboss::LERequestPeerSCACompleteSubeventView>();
177 }
178 case hci_spec::kLEAdvertisingSetTerminatedSubeventCode: {
179 return StatusCodeFromView<
180 pw::bluetooth::emboss::LEAdvertisingSetTerminatedSubeventView>();
181 }
182 default: {
183 PW_CRASH("Emboss LE meta subevent (%#.2x) not implemented",
184 subevent_code);
185 break;
186 }
187 }
188
189 break;
190 }
191
192 default: {
193 PW_CRASH("Emboss event (%#.2x) not implemented", event_code());
194 break;
195 }
196 }
197
198 return std::nullopt;
199 }
200
ToResult() const201 hci::Result<> EventPacket::ToResult() const {
202 std::optional<pw::bluetooth::emboss::StatusCode> maybe_status_code =
203 StatusCode();
204 if (!maybe_status_code.has_value()) {
205 return bt::ToResult(HostError::kPacketMalformed);
206 }
207 return bt::ToResult(*maybe_status_code);
208 }
209
210 } // namespace bt::hci
211