• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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