• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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_proxy/proxy_host.h"
16 
17 #include "emboss_util.h"
18 #include "pw_assert/check.h"  // IWYU pragma: keep
19 #include "pw_bluetooth/hci_common.emb.h"
20 #include "pw_bluetooth/hci_h4.emb.h"
21 #include "pw_bluetooth_proxy/common.h"
22 #include "pw_log/log.h"
23 
24 namespace pw::bluetooth::proxy {
25 
ProxyHost(H4HciPacketSendFn && send_to_host_fn,H4HciPacketSendFn && send_to_controller_fn,uint16_t le_acl_credits_to_reserve)26 ProxyHost::ProxyHost(H4HciPacketSendFn&& send_to_host_fn,
27                      H4HciPacketSendFn&& send_to_controller_fn,
28                      uint16_t le_acl_credits_to_reserve)
29     : outward_send_to_host_fn_(std::move(send_to_host_fn)),
30       outward_send_to_controller_fn_(std::move(send_to_controller_fn)),
31       acl_data_channel_{le_acl_credits_to_reserve} {}
32 
HandleH4HciFromHost(H4HciPacket h4_packet)33 void ProxyHost::HandleH4HciFromHost(H4HciPacket h4_packet) {
34   SendToController(h4_packet);
35 }
36 
ProcessH4HciFromController(H4HciPacket h4_packet)37 void ProxyHost::ProcessH4HciFromController(H4HciPacket h4_packet) {
38   if (h4_packet.hci_span.empty()) {
39     PW_LOG_ERROR("Received empty H4 buffer. So will not process.");
40     return;
41   }
42 
43   if (h4_packet.h4_type != emboss::H4PacketType::EVENT) {
44     return;
45   }
46   pw::span hci_buffer = h4_packet.hci_span;
47   auto event = MakeEmboss<emboss::EventHeaderView>(hci_buffer);
48   if (!event.IsComplete()) {
49     PW_LOG_ERROR("Buffer is too small for EventHeader. So will not process.");
50     return;
51   }
52 
53   if (event.event_code_enum().Read() != emboss::EventCode::COMMAND_COMPLETE) {
54     return;
55   }
56   auto command_complete_event =
57       MakeEmboss<emboss::CommandCompleteEventView>(hci_buffer);
58   if (!command_complete_event.IsComplete()) {
59     PW_LOG_ERROR(
60         "Buffer is too small for COMMAND_COMPLETE event. So will not process.");
61     return;
62   }
63 
64   PW_MODIFY_DIAGNOSTICS_PUSH();
65   PW_MODIFY_DIAGNOSTIC(ignored, "-Wswitch-enum");
66   switch (command_complete_event.command_opcode_enum().Read()) {
67     case emboss::OpCode::LE_READ_BUFFER_SIZE_V1: {
68       auto read_event =
69           MakeEmboss<emboss::LEReadBufferSizeV1CommandCompleteEventWriter>(
70               hci_buffer);
71       if (!read_event.IsComplete()) {
72         PW_LOG_ERROR(
73             "Buffer is too small for LE_READ_BUFFER_SIZE_V1 command complete "
74             "event. So will not process.");
75         return;
76       }
77       acl_data_channel_.ProcessLEReadBufferSizeCommandCompleteEvent(read_event);
78       break;
79     }
80     case emboss::OpCode::LE_READ_BUFFER_SIZE_V2: {
81       auto read_event =
82           MakeEmboss<emboss::LEReadBufferSizeV2CommandCompleteEventWriter>(
83               hci_buffer);
84       if (!read_event.IsComplete()) {
85         PW_LOG_ERROR(
86             "Buffer is too small for LE_READ_BUFFER_SIZE_V2 command complete "
87             "event. So will not process.");
88         return;
89       }
90       acl_data_channel_.ProcessLEReadBufferSizeCommandCompleteEvent(read_event);
91       break;
92     }
93     default:
94       // Nothing to process
95       break;
96   }
97   PW_MODIFY_DIAGNOSTICS_POP();
98 }
99 
HandleH4HciFromController(H4HciPacket h4_packet)100 void ProxyHost::HandleH4HciFromController(H4HciPacket h4_packet) {
101   ProcessH4HciFromController(h4_packet);
102   SendToHost(h4_packet);
103 }
104 
SendToHost(H4HciPacket h4_packet)105 void ProxyHost::SendToHost(H4HciPacket h4_packet) {
106   PW_DCHECK(outward_send_to_host_fn_ != nullptr);
107   outward_send_to_host_fn_(h4_packet);
108 }
109 
SendToController(H4HciPacket h4_packet)110 void ProxyHost::SendToController(H4HciPacket h4_packet) {
111   PW_DCHECK(outward_send_to_controller_fn_ != nullptr);
112   outward_send_to_controller_fn_(h4_packet);
113 }
114 
HasSendAclCapability() const115 bool ProxyHost::HasSendAclCapability() const {
116   return acl_data_channel_.GetLeAclCreditsToReserve() > 0;
117 }
118 
GetNumFreeLeAclPackets() const119 uint16_t ProxyHost::GetNumFreeLeAclPackets() const {
120   return acl_data_channel_.GetNumFreeLeAclPackets();
121 }
122 
123 }  // namespace pw::bluetooth::proxy
124