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/emboss_control_packets.h"
16
17 #include <pw_bluetooth/hci_android.emb.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/packet_view.h"
20 #include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
21
22 namespace bt::hci {
23
EmbossCommandPacket(hci_spec::OpCode opcode,size_t packet_size)24 EmbossCommandPacket::EmbossCommandPacket(hci_spec::OpCode opcode,
25 size_t packet_size)
26 : DynamicPacket(packet_size) {
27 BT_ASSERT_MSG(
28 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().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 EmbossCommandPacket::opcode() const {
39 return header_view().opcode().BackingStorage().ReadUInt();
40 }
41
ogf() const42 uint8_t EmbossCommandPacket::ogf() const {
43 return header_view().opcode().ogf().Read();
44 }
45
ocf() const46 uint16_t EmbossCommandPacket::ocf() const {
47 return header_view().opcode().ocf().Read();
48 }
49
header_view() const50 pw::bluetooth::emboss::CommandHeaderView EmbossCommandPacket::header_view()
51 const {
52 return view<pw::bluetooth::emboss::CommandHeaderView>();
53 }
54
EmbossEventPacket(size_t packet_size)55 EmbossEventPacket::EmbossEventPacket(size_t packet_size)
56 : DynamicPacket(packet_size) {
57 BT_ASSERT_MSG(
58 packet_size >= pw::bluetooth::emboss::EventHeader::IntrinsicSizeInBytes(),
59 "event packet size must be at least 2 bytes to accomodate header");
60 }
61
event_code() const62 hci_spec::EventCode EmbossEventPacket::event_code() const {
63 return view<pw::bluetooth::emboss::EventHeaderView>().event_code().Read();
64 }
65
StatusCode() const66 std::optional<pw::bluetooth::emboss::StatusCode> EmbossEventPacket::StatusCode()
67 const {
68 switch (event_code()) {
69 case hci_spec::kCommandCompleteEventCode:
70 return StatusCodeFromView<
71 pw::bluetooth::emboss::SimpleCommandCompleteEventView>();
72 case hci_spec ::kCommandStatusEventCode:
73 return StatusCodeFromView<
74 pw::bluetooth::emboss::CommandStatusEventView>();
75 case hci_spec::kConnectionCompleteEventCode:
76 return StatusCodeFromView<
77 pw::bluetooth::emboss::ConnectionCompleteEventView>();
78 case hci_spec::kDisconnectionCompleteEventCode:
79 return StatusCodeFromView<
80 pw::bluetooth::emboss::DisconnectionCompleteEventView>();
81 case hci_spec::kReadRemoteVersionInfoCompleteEventCode:
82 return StatusCodeFromView<
83 pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventView>();
84 case hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode:
85 return StatusCodeFromView<
86 pw::bluetooth::emboss::
87 ReadRemoteSupportedFeaturesCompleteEventView>();
88 case hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode:
89 return StatusCodeFromView<
90 pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventView>();
91 case hci_spec::kRemoteNameRequestCompleteEventCode: {
92 // Tests expect that a kPacketMalformed status is returned for incomplete
93 // events, even if they contain the status field.
94 pw::bluetooth::emboss::RemoteNameRequestCompleteEventView event_view(
95 data().data(), size());
96 if (!event_view.IsComplete()) {
97 return std::nullopt;
98 }
99 return event_view.status().UncheckedRead();
100 }
101 case hci_spec::kEncryptionChangeEventCode:
102 return StatusCodeFromView<
103 pw::bluetooth::emboss::EncryptionChangeEventV1View>();
104 case hci_spec::kEncryptionKeyRefreshCompleteEventCode:
105 return StatusCodeFromView<
106 pw::bluetooth::emboss::EncryptionKeyRefreshCompleteEventView>();
107 case hci_spec::kRoleChangeEventCode:
108 return StatusCodeFromView<pw::bluetooth::emboss::RoleChangeEventView>();
109 case hci_spec::kSynchronousConnectionCompleteEventCode:
110 return StatusCodeFromView<
111 pw::bluetooth::emboss::SynchronousConnectionCompleteEventView>();
112 case hci_spec::kVendorDebugEventCode: {
113 hci_spec::EventCode subevent_code =
114 view<pw::bluetooth::emboss::VendorDebugEventView>()
115 .subevent_code()
116 .Read();
117
118 switch (subevent_code) {
119 case hci_spec::vendor::android::kLEMultiAdvtStateChangeSubeventCode: {
120 return StatusCodeFromView<pw::bluetooth::vendor::android_hci::
121 LEMultiAdvtStateChangeSubeventView>();
122 }
123
124 default: {
125 BT_PANIC("Emboss vendor subevent (%#.2x) not implemented",
126 subevent_code);
127 break;
128 }
129 }
130
131 break;
132 }
133
134 case hci_spec::kLEMetaEventCode: {
135 hci_spec::EventCode subevent_code =
136 view<pw::bluetooth::emboss::LEMetaEventView>().subevent_code().Read();
137
138 switch (subevent_code) {
139 case hci_spec::kLEConnectionCompleteSubeventCode: {
140 return StatusCodeFromView<
141 pw::bluetooth::emboss::LEConnectionCompleteSubeventView>();
142 }
143
144 case hci_spec::kLEConnectionUpdateCompleteSubeventCode: {
145 return StatusCodeFromView<
146 pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventView>();
147 }
148
149 case hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode: {
150 return StatusCodeFromView<
151 pw::bluetooth::emboss::
152 LEReadRemoteFeaturesCompleteSubeventView>();
153 }
154
155 default: {
156 BT_PANIC("Emboss LE meta subevent (%#.2x) not implemented",
157 subevent_code);
158 break;
159 }
160 }
161
162 break;
163 }
164
165 default: {
166 BT_PANIC("Emboss event (%#.2x) not implemented", event_code());
167 break;
168 }
169 }
170
171 return std::nullopt;
172 }
173
ToResult() const174 hci::Result<> EmbossEventPacket::ToResult() const {
175 std::optional<pw::bluetooth::emboss::StatusCode> maybe_status_code =
176 StatusCode();
177 if (!maybe_status_code.has_value()) {
178 return bt::ToResult(HostError::kPacketMalformed);
179 }
180 return bt::ToResult(*maybe_status_code);
181 }
182
183 } // namespace bt::hci
184