xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/proxy_host.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_proxy/proxy_host.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"  // IWYU pragma: keep
18*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth/emboss_util.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth/hci_common.emb.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth/hci_data.emb.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth/l2cap_frames.emb.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_proxy/h4_packet.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_proxy/internal/gatt_notify_channel_internal.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_proxy/internal/l2cap_coc_internal.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_bluetooth_proxy/internal/logical_transport.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
27*61c4878aSAndroid Build Coastguard Worker 
28*61c4878aSAndroid Build Coastguard Worker namespace pw::bluetooth::proxy {
29*61c4878aSAndroid Build Coastguard Worker 
ProxyHost(pw::Function<void (H4PacketWithHci && packet)> && send_to_host_fn,pw::Function<void (H4PacketWithH4 && packet)> && send_to_controller_fn,uint16_t le_acl_credits_to_reserve,uint16_t br_edr_acl_credits_to_reserve)30*61c4878aSAndroid Build Coastguard Worker ProxyHost::ProxyHost(
31*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(H4PacketWithHci&& packet)>&& send_to_host_fn,
32*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(H4PacketWithH4&& packet)>&& send_to_controller_fn,
33*61c4878aSAndroid Build Coastguard Worker     uint16_t le_acl_credits_to_reserve,
34*61c4878aSAndroid Build Coastguard Worker     uint16_t br_edr_acl_credits_to_reserve)
35*61c4878aSAndroid Build Coastguard Worker     : hci_transport_(std::move(send_to_host_fn),
36*61c4878aSAndroid Build Coastguard Worker                      std::move(send_to_controller_fn)),
37*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_(hci_transport_,
38*61c4878aSAndroid Build Coastguard Worker                         l2cap_channel_manager_,
39*61c4878aSAndroid Build Coastguard Worker                         le_acl_credits_to_reserve,
40*61c4878aSAndroid Build Coastguard Worker                         br_edr_acl_credits_to_reserve),
41*61c4878aSAndroid Build Coastguard Worker       l2cap_channel_manager_(acl_data_channel_) {}
42*61c4878aSAndroid Build Coastguard Worker 
~ProxyHost()43*61c4878aSAndroid Build Coastguard Worker ProxyHost::~ProxyHost() { acl_data_channel_.Reset(); }
44*61c4878aSAndroid Build Coastguard Worker 
HandleH4HciFromHost(H4PacketWithH4 && h4_packet)45*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleH4HciFromHost(H4PacketWithH4&& h4_packet) {
46*61c4878aSAndroid Build Coastguard Worker   if (h4_packet.GetH4Type() == emboss::H4PacketType::ACL_DATA) {
47*61c4878aSAndroid Build Coastguard Worker     HandleAclFromHost(std::move(h4_packet));
48*61c4878aSAndroid Build Coastguard Worker     return;
49*61c4878aSAndroid Build Coastguard Worker   }
50*61c4878aSAndroid Build Coastguard Worker   hci_transport_.SendToController(std::move(h4_packet));
51*61c4878aSAndroid Build Coastguard Worker }
52*61c4878aSAndroid Build Coastguard Worker 
HandleH4HciFromController(H4PacketWithHci && h4_packet)53*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleH4HciFromController(H4PacketWithHci&& h4_packet) {
54*61c4878aSAndroid Build Coastguard Worker   if (h4_packet.GetH4Type() == emboss::H4PacketType::EVENT) {
55*61c4878aSAndroid Build Coastguard Worker     HandleEventFromController(std::move(h4_packet));
56*61c4878aSAndroid Build Coastguard Worker     return;
57*61c4878aSAndroid Build Coastguard Worker   }
58*61c4878aSAndroid Build Coastguard Worker   if (h4_packet.GetH4Type() == emboss::H4PacketType::ACL_DATA) {
59*61c4878aSAndroid Build Coastguard Worker     HandleAclFromController(std::move(h4_packet));
60*61c4878aSAndroid Build Coastguard Worker     return;
61*61c4878aSAndroid Build Coastguard Worker   }
62*61c4878aSAndroid Build Coastguard Worker   hci_transport_.SendToHost(std::move(h4_packet));
63*61c4878aSAndroid Build Coastguard Worker }
64*61c4878aSAndroid Build Coastguard Worker 
CheckForActiveFragmenting(AclDataChannel::Direction direction,emboss::AclDataFrameWriter & acl)65*61c4878aSAndroid Build Coastguard Worker bool ProxyHost::CheckForActiveFragmenting(AclDataChannel::Direction direction,
66*61c4878aSAndroid Build Coastguard Worker                                           emboss::AclDataFrameWriter& acl) {
67*61c4878aSAndroid Build Coastguard Worker   const uint16_t handle = acl.header().handle().Read();
68*61c4878aSAndroid Build Coastguard Worker   const emboss::AclDataPacketBoundaryFlag boundary_flag =
69*61c4878aSAndroid Build Coastguard Worker       acl.header().packet_boundary_flag().Read();
70*61c4878aSAndroid Build Coastguard Worker 
71*61c4878aSAndroid Build Coastguard Worker   pw::Result<bool> connection_is_receiving_fragmented_pdu =
72*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.IsReceivingFragmentedPdu(direction, handle);
73*61c4878aSAndroid Build Coastguard Worker   if (connection_is_receiving_fragmented_pdu.ok() &&
74*61c4878aSAndroid Build Coastguard Worker       *connection_is_receiving_fragmented_pdu) {
75*61c4878aSAndroid Build Coastguard Worker     // We're in a state where this connection is dropping continuing fragments
76*61c4878aSAndroid Build Coastguard Worker     // in a fragmented PDU.
77*61c4878aSAndroid Build Coastguard Worker     if (boundary_flag !=
78*61c4878aSAndroid Build Coastguard Worker         emboss::AclDataPacketBoundaryFlag::CONTINUING_FRAGMENT) {
79*61c4878aSAndroid Build Coastguard Worker       // The fragmented PDU has been fully received, so note that then proceed
80*61c4878aSAndroid Build Coastguard Worker       // to process the new PDU as normal.
81*61c4878aSAndroid Build Coastguard Worker       PW_CHECK(acl_data_channel_.FragmentedPduFinished(direction, handle).ok());
82*61c4878aSAndroid Build Coastguard Worker     } else {
83*61c4878aSAndroid Build Coastguard Worker       PW_LOG_INFO("(Connection: 0x%X) Dropping continuing PDU fragment.",
84*61c4878aSAndroid Build Coastguard Worker                   handle);
85*61c4878aSAndroid Build Coastguard Worker       return true;
86*61c4878aSAndroid Build Coastguard Worker     }
87*61c4878aSAndroid Build Coastguard Worker   }
88*61c4878aSAndroid Build Coastguard Worker   return false;
89*61c4878aSAndroid Build Coastguard Worker }
90*61c4878aSAndroid Build Coastguard Worker 
CheckForFragmentedStart(AclDataChannel::Direction direction,emboss::AclDataFrameWriter & acl,emboss::BasicL2capHeaderView & l2cap_header,L2capReadChannel * channel)91*61c4878aSAndroid Build Coastguard Worker bool ProxyHost::CheckForFragmentedStart(
92*61c4878aSAndroid Build Coastguard Worker     AclDataChannel::Direction direction,
93*61c4878aSAndroid Build Coastguard Worker     emboss::AclDataFrameWriter& acl,
94*61c4878aSAndroid Build Coastguard Worker     emboss::BasicL2capHeaderView& l2cap_header,
95*61c4878aSAndroid Build Coastguard Worker     L2capReadChannel* channel) {
96*61c4878aSAndroid Build Coastguard Worker   const uint16_t handle = acl.header().handle().Read();
97*61c4878aSAndroid Build Coastguard Worker   const emboss::AclDataPacketBoundaryFlag boundary_flag =
98*61c4878aSAndroid Build Coastguard Worker       acl.header().packet_boundary_flag().Read();
99*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/365179076 - Support recombination.
100*61c4878aSAndroid Build Coastguard Worker   if (boundary_flag == emboss::AclDataPacketBoundaryFlag::CONTINUING_FRAGMENT) {
101*61c4878aSAndroid Build Coastguard Worker     PW_LOG_INFO("(CID: 0x%X) Received unexpected continuing PDU fragment.",
102*61c4878aSAndroid Build Coastguard Worker                 handle);
103*61c4878aSAndroid Build Coastguard Worker     channel->OnFragmentedPduReceived();
104*61c4878aSAndroid Build Coastguard Worker     return true;
105*61c4878aSAndroid Build Coastguard Worker   }
106*61c4878aSAndroid Build Coastguard Worker   const uint16_t l2cap_frame_length =
107*61c4878aSAndroid Build Coastguard Worker       emboss::BasicL2capHeader::IntrinsicSizeInBytes() +
108*61c4878aSAndroid Build Coastguard Worker       l2cap_header.pdu_length().Read();
109*61c4878aSAndroid Build Coastguard Worker   if (l2cap_frame_length > acl.data_total_length().Read()) {
110*61c4878aSAndroid Build Coastguard Worker     pw::Status status =
111*61c4878aSAndroid Build Coastguard Worker         acl_data_channel_.FragmentedPduStarted(direction, handle);
112*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(status.ok());
113*61c4878aSAndroid Build Coastguard Worker     channel->OnFragmentedPduReceived();
114*61c4878aSAndroid Build Coastguard Worker     return true;
115*61c4878aSAndroid Build Coastguard Worker   }
116*61c4878aSAndroid Build Coastguard Worker 
117*61c4878aSAndroid Build Coastguard Worker   return false;
118*61c4878aSAndroid Build Coastguard Worker }
119*61c4878aSAndroid Build Coastguard Worker 
HandleEventFromController(H4PacketWithHci && h4_packet)120*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleEventFromController(H4PacketWithHci&& h4_packet) {
121*61c4878aSAndroid Build Coastguard Worker   pw::span<uint8_t> hci_buffer = h4_packet.GetHciSpan();
122*61c4878aSAndroid Build Coastguard Worker   Result<emboss::EventHeaderView> event =
123*61c4878aSAndroid Build Coastguard Worker       MakeEmbossView<emboss::EventHeaderView>(hci_buffer);
124*61c4878aSAndroid Build Coastguard Worker   if (!event.ok()) {
125*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
126*61c4878aSAndroid Build Coastguard Worker         "Buffer is too small for EventHeader. So will pass on to host without "
127*61c4878aSAndroid Build Coastguard Worker         "processing.");
128*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
129*61c4878aSAndroid Build Coastguard Worker     return;
130*61c4878aSAndroid Build Coastguard Worker   }
131*61c4878aSAndroid Build Coastguard Worker 
132*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_PUSH();
133*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
134*61c4878aSAndroid Build Coastguard Worker   switch (event->event_code_enum().Read()) {
135*61c4878aSAndroid Build Coastguard Worker     case emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS: {
136*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleNumberOfCompletedPacketsEvent(
137*61c4878aSAndroid Build Coastguard Worker           std::move(h4_packet));
138*61c4878aSAndroid Build Coastguard Worker       break;
139*61c4878aSAndroid Build Coastguard Worker     }
140*61c4878aSAndroid Build Coastguard Worker     case emboss::EventCode::DISCONNECTION_COMPLETE: {
141*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleDisconnectionCompleteEvent(std::move(h4_packet));
142*61c4878aSAndroid Build Coastguard Worker       break;
143*61c4878aSAndroid Build Coastguard Worker     }
144*61c4878aSAndroid Build Coastguard Worker     case emboss::EventCode::COMMAND_COMPLETE: {
145*61c4878aSAndroid Build Coastguard Worker       HandleCommandCompleteEvent(std::move(h4_packet));
146*61c4878aSAndroid Build Coastguard Worker       break;
147*61c4878aSAndroid Build Coastguard Worker     }
148*61c4878aSAndroid Build Coastguard Worker     case emboss::EventCode::CONNECTION_COMPLETE: {
149*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleConnectionCompleteEvent(std::move(h4_packet));
150*61c4878aSAndroid Build Coastguard Worker       break;
151*61c4878aSAndroid Build Coastguard Worker     }
152*61c4878aSAndroid Build Coastguard Worker     case emboss::EventCode::LE_META_EVENT: {
153*61c4878aSAndroid Build Coastguard Worker       HandleLeMetaEvent(std::move(h4_packet));
154*61c4878aSAndroid Build Coastguard Worker       break;
155*61c4878aSAndroid Build Coastguard Worker     }
156*61c4878aSAndroid Build Coastguard Worker     default: {
157*61c4878aSAndroid Build Coastguard Worker       hci_transport_.SendToHost(std::move(h4_packet));
158*61c4878aSAndroid Build Coastguard Worker       return;
159*61c4878aSAndroid Build Coastguard Worker     }
160*61c4878aSAndroid Build Coastguard Worker   }
161*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_POP();
162*61c4878aSAndroid Build Coastguard Worker }
163*61c4878aSAndroid Build Coastguard Worker 
HandleAclFromController(H4PacketWithHci && h4_packet)164*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleAclFromController(H4PacketWithHci&& h4_packet) {
165*61c4878aSAndroid Build Coastguard Worker   pw::span<uint8_t> hci_buffer = h4_packet.GetHciSpan();
166*61c4878aSAndroid Build Coastguard Worker 
167*61c4878aSAndroid Build Coastguard Worker   Result<emboss::AclDataFrameWriter> acl =
168*61c4878aSAndroid Build Coastguard Worker       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_buffer);
169*61c4878aSAndroid Build Coastguard Worker   if (!acl.ok()) {
170*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
171*61c4878aSAndroid Build Coastguard Worker         "Buffer is too small for ACL header. So will pass on to host.");
172*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
173*61c4878aSAndroid Build Coastguard Worker     return;
174*61c4878aSAndroid Build Coastguard Worker   }
175*61c4878aSAndroid Build Coastguard Worker   const uint16_t handle = acl->header().handle().Read();
176*61c4878aSAndroid Build Coastguard Worker 
177*61c4878aSAndroid Build Coastguard Worker   if (CheckForActiveFragmenting(AclDataChannel::Direction::kFromController,
178*61c4878aSAndroid Build Coastguard Worker                                 *acl)) {
179*61c4878aSAndroid Build Coastguard Worker     return;
180*61c4878aSAndroid Build Coastguard Worker   }
181*61c4878aSAndroid Build Coastguard Worker 
182*61c4878aSAndroid Build Coastguard Worker   emboss::BasicL2capHeaderView l2cap_header = emboss::MakeBasicL2capHeaderView(
183*61c4878aSAndroid Build Coastguard Worker       acl->payload().BackingStorage().data(),
184*61c4878aSAndroid Build Coastguard Worker       acl->payload().BackingStorage().SizeInBytes());
185*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/365179076 - Technically, the first fragment of a
186*61c4878aSAndroid Build Coastguard Worker   // fragmented PDU may include an incomplete L2CAP header.
187*61c4878aSAndroid Build Coastguard Worker   if (!l2cap_header.Ok()) {
188*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
189*61c4878aSAndroid Build Coastguard Worker         "(Connection: 0x%X) ACL packet does not include a valid L2CAP header. "
190*61c4878aSAndroid Build Coastguard Worker         "So will pass on to host.",
191*61c4878aSAndroid Build Coastguard Worker         handle);
192*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
193*61c4878aSAndroid Build Coastguard Worker     return;
194*61c4878aSAndroid Build Coastguard Worker   }
195*61c4878aSAndroid Build Coastguard Worker 
196*61c4878aSAndroid Build Coastguard Worker   L2capReadChannel* channel = l2cap_channel_manager_.FindReadChannel(
197*61c4878aSAndroid Build Coastguard Worker       acl->header().handle().Read(), l2cap_header.channel_id().Read());
198*61c4878aSAndroid Build Coastguard Worker   if (!channel) {
199*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
200*61c4878aSAndroid Build Coastguard Worker     return;
201*61c4878aSAndroid Build Coastguard Worker   }
202*61c4878aSAndroid Build Coastguard Worker 
203*61c4878aSAndroid Build Coastguard Worker   if (CheckForFragmentedStart(AclDataChannel::Direction::kFromController,
204*61c4878aSAndroid Build Coastguard Worker                               *acl,
205*61c4878aSAndroid Build Coastguard Worker                               l2cap_header,
206*61c4878aSAndroid Build Coastguard Worker                               channel)) {
207*61c4878aSAndroid Build Coastguard Worker     return;
208*61c4878aSAndroid Build Coastguard Worker   }
209*61c4878aSAndroid Build Coastguard Worker 
210*61c4878aSAndroid Build Coastguard Worker   if (!channel->HandlePduFromController(
211*61c4878aSAndroid Build Coastguard Worker           pw::span(acl->payload().BackingStorage().data(),
212*61c4878aSAndroid Build Coastguard Worker                    acl->payload().SizeInBytes()))) {
213*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
214*61c4878aSAndroid Build Coastguard Worker   }
215*61c4878aSAndroid Build Coastguard Worker }
216*61c4878aSAndroid Build Coastguard Worker 
HandleLeMetaEvent(H4PacketWithHci && h4_packet)217*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleLeMetaEvent(H4PacketWithHci&& h4_packet) {
218*61c4878aSAndroid Build Coastguard Worker   pw::span<uint8_t> hci_buffer = h4_packet.GetHciSpan();
219*61c4878aSAndroid Build Coastguard Worker   Result<emboss::LEMetaEventView> le_meta_event_view =
220*61c4878aSAndroid Build Coastguard Worker       MakeEmbossView<emboss::LEMetaEventView>(hci_buffer);
221*61c4878aSAndroid Build Coastguard Worker   if (!le_meta_event_view.ok()) {
222*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
223*61c4878aSAndroid Build Coastguard Worker         "Buffer is too small for LE_META_EVENT event. So will not process.");
224*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
225*61c4878aSAndroid Build Coastguard Worker     return;
226*61c4878aSAndroid Build Coastguard Worker   }
227*61c4878aSAndroid Build Coastguard Worker 
228*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_PUSH();
229*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
230*61c4878aSAndroid Build Coastguard Worker   switch (le_meta_event_view->subevent_code_enum().Read()) {
231*61c4878aSAndroid Build Coastguard Worker     case emboss::LeSubEventCode::CONNECTION_COMPLETE: {
232*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleLeConnectionCompleteEvent(std::move(h4_packet));
233*61c4878aSAndroid Build Coastguard Worker       return;
234*61c4878aSAndroid Build Coastguard Worker     }
235*61c4878aSAndroid Build Coastguard Worker     case emboss::LeSubEventCode::ENHANCED_CONNECTION_COMPLETE_V1: {
236*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleLeEnhancedConnectionCompleteV1Event(
237*61c4878aSAndroid Build Coastguard Worker           std::move(h4_packet));
238*61c4878aSAndroid Build Coastguard Worker       return;
239*61c4878aSAndroid Build Coastguard Worker     }
240*61c4878aSAndroid Build Coastguard Worker     case emboss::LeSubEventCode::ENHANCED_CONNECTION_COMPLETE_V2: {
241*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.HandleLeEnhancedConnectionCompleteV2Event(
242*61c4878aSAndroid Build Coastguard Worker           std::move(h4_packet));
243*61c4878aSAndroid Build Coastguard Worker       return;
244*61c4878aSAndroid Build Coastguard Worker     }
245*61c4878aSAndroid Build Coastguard Worker     default:
246*61c4878aSAndroid Build Coastguard Worker       break;
247*61c4878aSAndroid Build Coastguard Worker   }
248*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_POP();
249*61c4878aSAndroid Build Coastguard Worker   hci_transport_.SendToHost(std::move(h4_packet));
250*61c4878aSAndroid Build Coastguard Worker }
251*61c4878aSAndroid Build Coastguard Worker 
HandleCommandCompleteEvent(H4PacketWithHci && h4_packet)252*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleCommandCompleteEvent(H4PacketWithHci&& h4_packet) {
253*61c4878aSAndroid Build Coastguard Worker   pw::span<uint8_t> hci_buffer = h4_packet.GetHciSpan();
254*61c4878aSAndroid Build Coastguard Worker   Result<emboss::CommandCompleteEventView> command_complete_event =
255*61c4878aSAndroid Build Coastguard Worker       MakeEmbossView<emboss::CommandCompleteEventView>(hci_buffer);
256*61c4878aSAndroid Build Coastguard Worker   if (!command_complete_event.ok()) {
257*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
258*61c4878aSAndroid Build Coastguard Worker         "Buffer is too small for COMMAND_COMPLETE event. So will not process.");
259*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToHost(std::move(h4_packet));
260*61c4878aSAndroid Build Coastguard Worker     return;
261*61c4878aSAndroid Build Coastguard Worker   }
262*61c4878aSAndroid Build Coastguard Worker 
263*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_PUSH();
264*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
265*61c4878aSAndroid Build Coastguard Worker   switch (command_complete_event->command_opcode_enum().Read()) {
266*61c4878aSAndroid Build Coastguard Worker     case emboss::OpCode::READ_BUFFER_SIZE: {
267*61c4878aSAndroid Build Coastguard Worker       Result<emboss::ReadBufferSizeCommandCompleteEventWriter> read_event =
268*61c4878aSAndroid Build Coastguard Worker           MakeEmbossWriter<emboss::ReadBufferSizeCommandCompleteEventWriter>(
269*61c4878aSAndroid Build Coastguard Worker               hci_buffer);
270*61c4878aSAndroid Build Coastguard Worker       if (!read_event.ok()) {
271*61c4878aSAndroid Build Coastguard Worker         PW_LOG_ERROR(
272*61c4878aSAndroid Build Coastguard Worker             "Buffer is too small for READ_BUFFER_SIZE command complete event. "
273*61c4878aSAndroid Build Coastguard Worker             "Will not process.");
274*61c4878aSAndroid Build Coastguard Worker         break;
275*61c4878aSAndroid Build Coastguard Worker       }
276*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.ProcessReadBufferSizeCommandCompleteEvent(*read_event);
277*61c4878aSAndroid Build Coastguard Worker       break;
278*61c4878aSAndroid Build Coastguard Worker     }
279*61c4878aSAndroid Build Coastguard Worker     case emboss::OpCode::LE_READ_BUFFER_SIZE_V1: {
280*61c4878aSAndroid Build Coastguard Worker       Result<emboss::LEReadBufferSizeV1CommandCompleteEventWriter> read_event =
281*61c4878aSAndroid Build Coastguard Worker           MakeEmbossWriter<
282*61c4878aSAndroid Build Coastguard Worker               emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(hci_buffer);
283*61c4878aSAndroid Build Coastguard Worker       if (!read_event.ok()) {
284*61c4878aSAndroid Build Coastguard Worker         PW_LOG_ERROR(
285*61c4878aSAndroid Build Coastguard Worker             "Buffer is too small for LE_READ_BUFFER_SIZE_V1 command complete "
286*61c4878aSAndroid Build Coastguard Worker             "event. So will not process.");
287*61c4878aSAndroid Build Coastguard Worker         break;
288*61c4878aSAndroid Build Coastguard Worker       }
289*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.ProcessLEReadBufferSizeCommandCompleteEvent(
290*61c4878aSAndroid Build Coastguard Worker           *read_event);
291*61c4878aSAndroid Build Coastguard Worker       break;
292*61c4878aSAndroid Build Coastguard Worker     }
293*61c4878aSAndroid Build Coastguard Worker     case emboss::OpCode::LE_READ_BUFFER_SIZE_V2: {
294*61c4878aSAndroid Build Coastguard Worker       Result<emboss::LEReadBufferSizeV2CommandCompleteEventWriter> read_event =
295*61c4878aSAndroid Build Coastguard Worker           MakeEmbossWriter<
296*61c4878aSAndroid Build Coastguard Worker               emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(hci_buffer);
297*61c4878aSAndroid Build Coastguard Worker       if (!read_event.ok()) {
298*61c4878aSAndroid Build Coastguard Worker         PW_LOG_ERROR(
299*61c4878aSAndroid Build Coastguard Worker             "Buffer is too small for LE_READ_BUFFER_SIZE_V2 command complete "
300*61c4878aSAndroid Build Coastguard Worker             "event. So will not process.");
301*61c4878aSAndroid Build Coastguard Worker         break;
302*61c4878aSAndroid Build Coastguard Worker       }
303*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.ProcessLEReadBufferSizeCommandCompleteEvent(
304*61c4878aSAndroid Build Coastguard Worker           *read_event);
305*61c4878aSAndroid Build Coastguard Worker       break;
306*61c4878aSAndroid Build Coastguard Worker     }
307*61c4878aSAndroid Build Coastguard Worker     default:
308*61c4878aSAndroid Build Coastguard Worker       break;
309*61c4878aSAndroid Build Coastguard Worker   }
310*61c4878aSAndroid Build Coastguard Worker   PW_MODIFY_DIAGNOSTICS_POP();
311*61c4878aSAndroid Build Coastguard Worker   hci_transport_.SendToHost(std::move(h4_packet));
312*61c4878aSAndroid Build Coastguard Worker }
313*61c4878aSAndroid Build Coastguard Worker 
HandleAclFromHost(H4PacketWithH4 && h4_packet)314*61c4878aSAndroid Build Coastguard Worker void ProxyHost::HandleAclFromHost(H4PacketWithH4&& h4_packet) {
315*61c4878aSAndroid Build Coastguard Worker   pw::span<uint8_t> hci_buffer = h4_packet.GetHciSpan();
316*61c4878aSAndroid Build Coastguard Worker 
317*61c4878aSAndroid Build Coastguard Worker   Result<emboss::AclDataFrameWriter> acl =
318*61c4878aSAndroid Build Coastguard Worker       MakeEmbossWriter<emboss::AclDataFrameWriter>(hci_buffer);
319*61c4878aSAndroid Build Coastguard Worker   if (!acl.ok()) {
320*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
321*61c4878aSAndroid Build Coastguard Worker         "Buffer is too small for ACL header. So will pass on to controller.");
322*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToController(std::move(h4_packet));
323*61c4878aSAndroid Build Coastguard Worker     return;
324*61c4878aSAndroid Build Coastguard Worker   }
325*61c4878aSAndroid Build Coastguard Worker 
326*61c4878aSAndroid Build Coastguard Worker   if (CheckForActiveFragmenting(AclDataChannel::Direction::kFromHost, *acl)) {
327*61c4878aSAndroid Build Coastguard Worker     return;
328*61c4878aSAndroid Build Coastguard Worker   }
329*61c4878aSAndroid Build Coastguard Worker 
330*61c4878aSAndroid Build Coastguard Worker   const uint16_t handle = acl->header().handle().Read();
331*61c4878aSAndroid Build Coastguard Worker   emboss::BasicL2capHeaderView l2cap_header = emboss::MakeBasicL2capHeaderView(
332*61c4878aSAndroid Build Coastguard Worker       acl->payload().BackingStorage().data(),
333*61c4878aSAndroid Build Coastguard Worker       acl->payload().BackingStorage().SizeInBytes());
334*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/365179076 - Technically, the first fragment of a
335*61c4878aSAndroid Build Coastguard Worker   // fragmented PDU may include an incomplete L2CAP header.
336*61c4878aSAndroid Build Coastguard Worker   if (!l2cap_header.Ok()) {
337*61c4878aSAndroid Build Coastguard Worker     PW_LOG_ERROR(
338*61c4878aSAndroid Build Coastguard Worker         "(Connection: 0x%X) ACL packet does not include a valid L2CAP header. "
339*61c4878aSAndroid Build Coastguard Worker         "So will pass on to controller.",
340*61c4878aSAndroid Build Coastguard Worker         handle);
341*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToController(std::move(h4_packet));
342*61c4878aSAndroid Build Coastguard Worker     return;
343*61c4878aSAndroid Build Coastguard Worker   }
344*61c4878aSAndroid Build Coastguard Worker 
345*61c4878aSAndroid Build Coastguard Worker   L2capReadChannel* channel = acl_data_channel_.FindSignalingChannel(
346*61c4878aSAndroid Build Coastguard Worker       acl->header().handle().Read(), l2cap_header.channel_id().Read());
347*61c4878aSAndroid Build Coastguard Worker   if (!channel) {
348*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToController(std::move(h4_packet));
349*61c4878aSAndroid Build Coastguard Worker 
350*61c4878aSAndroid Build Coastguard Worker     return;
351*61c4878aSAndroid Build Coastguard Worker   }
352*61c4878aSAndroid Build Coastguard Worker 
353*61c4878aSAndroid Build Coastguard Worker   if (CheckForFragmentedStart(
354*61c4878aSAndroid Build Coastguard Worker           AclDataChannel::Direction::kFromHost, *acl, l2cap_header, channel)) {
355*61c4878aSAndroid Build Coastguard Worker     return;
356*61c4878aSAndroid Build Coastguard Worker   }
357*61c4878aSAndroid Build Coastguard Worker 
358*61c4878aSAndroid Build Coastguard Worker   if (!channel->HandlePduFromHost(
359*61c4878aSAndroid Build Coastguard Worker           pw::span(acl->payload().BackingStorage().data(),
360*61c4878aSAndroid Build Coastguard Worker                    acl->payload().SizeInBytes()))) {
361*61c4878aSAndroid Build Coastguard Worker     hci_transport_.SendToController(std::move(h4_packet));
362*61c4878aSAndroid Build Coastguard Worker   }
363*61c4878aSAndroid Build Coastguard Worker }
364*61c4878aSAndroid Build Coastguard Worker 
Reset()365*61c4878aSAndroid Build Coastguard Worker void ProxyHost::Reset() {
366*61c4878aSAndroid Build Coastguard Worker   acl_data_channel_.Reset();
367*61c4878aSAndroid Build Coastguard Worker   l2cap_channel_manager_.Reset();
368*61c4878aSAndroid Build Coastguard Worker }
369*61c4878aSAndroid Build Coastguard Worker 
AcquireL2capCoc(uint16_t connection_handle,L2capCoc::CocConfig rx_config,L2capCoc::CocConfig tx_config,pw::Function<void (pw::span<uint8_t> payload)> && receive_fn,pw::Function<void (L2capCoc::Event event)> && event_fn,uint16_t rx_additional_credits)370*61c4878aSAndroid Build Coastguard Worker pw::Result<L2capCoc> ProxyHost::AcquireL2capCoc(
371*61c4878aSAndroid Build Coastguard Worker     uint16_t connection_handle,
372*61c4878aSAndroid Build Coastguard Worker     L2capCoc::CocConfig rx_config,
373*61c4878aSAndroid Build Coastguard Worker     L2capCoc::CocConfig tx_config,
374*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(pw::span<uint8_t> payload)>&& receive_fn,
375*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(L2capCoc::Event event)>&& event_fn,
376*61c4878aSAndroid Build Coastguard Worker     uint16_t rx_additional_credits) {
377*61c4878aSAndroid Build Coastguard Worker   Status status = acl_data_channel_.CreateAclConnection(connection_handle,
378*61c4878aSAndroid Build Coastguard Worker                                                         AclTransportType::kLe);
379*61c4878aSAndroid Build Coastguard Worker   if (status.IsResourceExhausted()) {
380*61c4878aSAndroid Build Coastguard Worker     return pw::Status::Unavailable();
381*61c4878aSAndroid Build Coastguard Worker   }
382*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(status.ok() || status.IsAlreadyExists());
383*61c4878aSAndroid Build Coastguard Worker   if (rx_additional_credits > 0) {
384*61c4878aSAndroid Build Coastguard Worker     L2capSignalingChannel* signaling_channel =
385*61c4878aSAndroid Build Coastguard Worker         acl_data_channel_.FindSignalingChannel(
386*61c4878aSAndroid Build Coastguard Worker             connection_handle,
387*61c4878aSAndroid Build Coastguard Worker             static_cast<uint16_t>(emboss::L2capFixedCid::LE_U_SIGNALING));
388*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(signaling_channel);
389*61c4878aSAndroid Build Coastguard Worker     status = signaling_channel->SendFlowControlCreditInd(rx_config.cid,
390*61c4878aSAndroid Build Coastguard Worker                                                          rx_additional_credits);
391*61c4878aSAndroid Build Coastguard Worker     if (!status.ok()) {
392*61c4878aSAndroid Build Coastguard Worker       return status;
393*61c4878aSAndroid Build Coastguard Worker     }
394*61c4878aSAndroid Build Coastguard Worker   }
395*61c4878aSAndroid Build Coastguard Worker   return L2capCocInternal::Create(l2cap_channel_manager_,
396*61c4878aSAndroid Build Coastguard Worker                                   connection_handle,
397*61c4878aSAndroid Build Coastguard Worker                                   rx_config,
398*61c4878aSAndroid Build Coastguard Worker                                   tx_config,
399*61c4878aSAndroid Build Coastguard Worker                                   std::move(receive_fn),
400*61c4878aSAndroid Build Coastguard Worker                                   std::move(event_fn));
401*61c4878aSAndroid Build Coastguard Worker }
402*61c4878aSAndroid Build Coastguard Worker 
AcquireBasicL2capChannel(uint16_t connection_handle,uint16_t local_cid,uint16_t remote_cid,AclTransportType transport,pw::Function<void (pw::span<uint8_t> payload)> && payload_from_controller_fn)403*61c4878aSAndroid Build Coastguard Worker pw::Result<BasicL2capChannel> ProxyHost::AcquireBasicL2capChannel(
404*61c4878aSAndroid Build Coastguard Worker     uint16_t connection_handle,
405*61c4878aSAndroid Build Coastguard Worker     uint16_t local_cid,
406*61c4878aSAndroid Build Coastguard Worker     uint16_t remote_cid,
407*61c4878aSAndroid Build Coastguard Worker     AclTransportType transport,
408*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(pw::span<uint8_t> payload)>&&
409*61c4878aSAndroid Build Coastguard Worker         payload_from_controller_fn) {
410*61c4878aSAndroid Build Coastguard Worker   Status status =
411*61c4878aSAndroid Build Coastguard Worker       acl_data_channel_.CreateAclConnection(connection_handle, transport);
412*61c4878aSAndroid Build Coastguard Worker   if (status.IsResourceExhausted()) {
413*61c4878aSAndroid Build Coastguard Worker     return pw::Status::Unavailable();
414*61c4878aSAndroid Build Coastguard Worker   }
415*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(status.ok() || status.IsAlreadyExists());
416*61c4878aSAndroid Build Coastguard Worker   return BasicL2capChannel::Create(
417*61c4878aSAndroid Build Coastguard Worker       /*l2cap_channel_manager=*/l2cap_channel_manager_,
418*61c4878aSAndroid Build Coastguard Worker       /*connection_handle=*/connection_handle,
419*61c4878aSAndroid Build Coastguard Worker       /*local_cid=*/local_cid,
420*61c4878aSAndroid Build Coastguard Worker       /*remote_cid=*/remote_cid,
421*61c4878aSAndroid Build Coastguard Worker       /*payload_from_controller_fn=*/std::move(payload_from_controller_fn));
422*61c4878aSAndroid Build Coastguard Worker }
423*61c4878aSAndroid Build Coastguard Worker 
SendGattNotify(uint16_t connection_handle,uint16_t attribute_handle,pw::span<const uint8_t> attribute_value)424*61c4878aSAndroid Build Coastguard Worker pw::Status ProxyHost::SendGattNotify(uint16_t connection_handle,
425*61c4878aSAndroid Build Coastguard Worker                                      uint16_t attribute_handle,
426*61c4878aSAndroid Build Coastguard Worker                                      pw::span<const uint8_t> attribute_value) {
427*61c4878aSAndroid Build Coastguard Worker   // TODO: https://pwbug.dev/369709521 - Migrate clients to channel API.
428*61c4878aSAndroid Build Coastguard Worker   Status status = acl_data_channel_.CreateAclConnection(connection_handle,
429*61c4878aSAndroid Build Coastguard Worker                                                         AclTransportType::kLe);
430*61c4878aSAndroid Build Coastguard Worker   if (status != OkStatus() && status != Status::AlreadyExists()) {
431*61c4878aSAndroid Build Coastguard Worker     return pw::Status::Unavailable();
432*61c4878aSAndroid Build Coastguard Worker   }
433*61c4878aSAndroid Build Coastguard Worker   pw::Result<GattNotifyChannel> channel_result =
434*61c4878aSAndroid Build Coastguard Worker       GattNotifyChannelInternal::Create(
435*61c4878aSAndroid Build Coastguard Worker           l2cap_channel_manager_, connection_handle, attribute_handle);
436*61c4878aSAndroid Build Coastguard Worker   if (!channel_result.ok()) {
437*61c4878aSAndroid Build Coastguard Worker     return channel_result.status();
438*61c4878aSAndroid Build Coastguard Worker   }
439*61c4878aSAndroid Build Coastguard Worker   return channel_result->Write(attribute_value);
440*61c4878aSAndroid Build Coastguard Worker }
441*61c4878aSAndroid Build Coastguard Worker 
AcquireRfcommChannel(uint16_t connection_handle,RfcommChannel::Config rx_config,RfcommChannel::Config tx_config,uint8_t channel_number,pw::Function<void (pw::span<uint8_t> payload)> && receive_fn)442*61c4878aSAndroid Build Coastguard Worker pw::Result<RfcommChannel> ProxyHost::AcquireRfcommChannel(
443*61c4878aSAndroid Build Coastguard Worker     uint16_t connection_handle,
444*61c4878aSAndroid Build Coastguard Worker     RfcommChannel::Config rx_config,
445*61c4878aSAndroid Build Coastguard Worker     RfcommChannel::Config tx_config,
446*61c4878aSAndroid Build Coastguard Worker     uint8_t channel_number,
447*61c4878aSAndroid Build Coastguard Worker     pw::Function<void(pw::span<uint8_t> payload)>&& receive_fn) {
448*61c4878aSAndroid Build Coastguard Worker   Status status = acl_data_channel_.CreateAclConnection(
449*61c4878aSAndroid Build Coastguard Worker       connection_handle, AclTransportType::kBrEdr);
450*61c4878aSAndroid Build Coastguard Worker   if (status != OkStatus() && status != Status::AlreadyExists()) {
451*61c4878aSAndroid Build Coastguard Worker     return pw::Status::Unavailable();
452*61c4878aSAndroid Build Coastguard Worker   }
453*61c4878aSAndroid Build Coastguard Worker   return RfcommChannel::Create(l2cap_channel_manager_,
454*61c4878aSAndroid Build Coastguard Worker                                connection_handle,
455*61c4878aSAndroid Build Coastguard Worker                                rx_config,
456*61c4878aSAndroid Build Coastguard Worker                                tx_config,
457*61c4878aSAndroid Build Coastguard Worker                                channel_number,
458*61c4878aSAndroid Build Coastguard Worker                                std::move(receive_fn));
459*61c4878aSAndroid Build Coastguard Worker }
460*61c4878aSAndroid Build Coastguard Worker 
HasSendLeAclCapability() const461*61c4878aSAndroid Build Coastguard Worker bool ProxyHost::HasSendLeAclCapability() const {
462*61c4878aSAndroid Build Coastguard Worker   return acl_data_channel_.HasSendAclCapability(AclTransportType::kLe);
463*61c4878aSAndroid Build Coastguard Worker }
464*61c4878aSAndroid Build Coastguard Worker 
HasSendBrEdrAclCapability() const465*61c4878aSAndroid Build Coastguard Worker bool ProxyHost::HasSendBrEdrAclCapability() const {
466*61c4878aSAndroid Build Coastguard Worker   return acl_data_channel_.HasSendAclCapability(AclTransportType::kBrEdr);
467*61c4878aSAndroid Build Coastguard Worker }
468*61c4878aSAndroid Build Coastguard Worker 
GetNumFreeLeAclPackets() const469*61c4878aSAndroid Build Coastguard Worker uint16_t ProxyHost::GetNumFreeLeAclPackets() const {
470*61c4878aSAndroid Build Coastguard Worker   return acl_data_channel_.GetNumFreeAclPackets(AclTransportType::kLe);
471*61c4878aSAndroid Build Coastguard Worker }
472*61c4878aSAndroid Build Coastguard Worker 
GetNumFreeBrEdrAclPackets() const473*61c4878aSAndroid Build Coastguard Worker uint16_t ProxyHost::GetNumFreeBrEdrAclPackets() const {
474*61c4878aSAndroid Build Coastguard Worker   return acl_data_channel_.GetNumFreeAclPackets(AclTransportType::kBrEdr);
475*61c4878aSAndroid Build Coastguard Worker }
476*61c4878aSAndroid Build Coastguard Worker 
477*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::bluetooth::proxy
478