xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/basic_l2cap_channel.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/basic_l2cap_channel.h"
16 
17 #include "pw_bluetooth/emboss_util.h"
18 #include "pw_bluetooth/hci_data.emb.h"
19 #include "pw_bluetooth/l2cap_frames.emb.h"
20 #include "pw_log/log.h"
21 #include "pw_status/try.h"
22 
23 namespace pw::bluetooth::proxy {
24 
Create(L2capChannelManager & l2cap_channel_manager,uint16_t connection_handle,uint16_t local_cid,uint16_t remote_cid,pw::Function<void (pw::span<uint8_t> payload)> && payload_from_controller_fn)25 pw::Result<BasicL2capChannel> BasicL2capChannel::Create(
26     L2capChannelManager& l2cap_channel_manager,
27     uint16_t connection_handle,
28     uint16_t local_cid,
29     uint16_t remote_cid,
30     pw::Function<void(pw::span<uint8_t> payload)>&&
31         payload_from_controller_fn) {
32   if (!L2capReadChannel::AreValidParameters(connection_handle, local_cid) ||
33       !L2capWriteChannel::AreValidParameters(connection_handle, remote_cid)) {
34     return pw::Status::InvalidArgument();
35   }
36 
37   return BasicL2capChannel(
38       /*l2cap_channel_manager=*/l2cap_channel_manager,
39       /*connection_handle=*/connection_handle,
40       /*local_cid=*/local_cid,
41       /*remote_cid=*/remote_cid,
42       /*payload_from_controller_fn=*/std::move(payload_from_controller_fn));
43 }
44 
Write(pw::span<const uint8_t> payload)45 pw::Status BasicL2capChannel::Write(pw::span<const uint8_t> payload) {
46   // TODO: https://pwbug.dev/360929142 - Reject payloads exceeding MTU.
47 
48   pw::Result<H4PacketWithH4> h4_result = PopulateTxL2capPacket(payload.size());
49   if (!h4_result.ok()) {
50     // This can fail as a result of the L2CAP PDU not fitting in an H4 buffer
51     // or if all buffers are occupied.
52     // TODO: https://pwbug.dev/365179076 - Once we support ACL fragmentation,
53     // this function will not fail due to the L2CAP PDU size not fitting.
54     return h4_result.status();
55   }
56   H4PacketWithH4 h4_packet = std::move(*h4_result);
57 
58   PW_TRY_ASSIGN(
59       auto acl,
60       MakeEmbossWriter<emboss::AclDataFrameWriter>(h4_packet.GetHciSpan()));
61   PW_TRY_ASSIGN(auto bframe,
62                 MakeEmbossWriter<emboss::BFrameWriter>(
63                     acl.payload().BackingStorage().data(),
64                     acl.payload().BackingStorage().SizeInBytes()));
65   std::memcpy(
66       bframe.payload().BackingStorage().data(), payload.data(), payload.size());
67 
68   return QueuePacket(std::move(h4_packet));
69 }
70 
BasicL2capChannel(L2capChannelManager & l2cap_channel_manager,uint16_t connection_handle,uint16_t local_cid,uint16_t remote_cid,pw::Function<void (pw::span<uint8_t> payload)> && payload_from_controller_fn)71 BasicL2capChannel::BasicL2capChannel(
72     L2capChannelManager& l2cap_channel_manager,
73     uint16_t connection_handle,
74     uint16_t local_cid,
75     uint16_t remote_cid,
76     pw::Function<void(pw::span<uint8_t> payload)>&& payload_from_controller_fn)
77     : L2capReadChannel(l2cap_channel_manager,
78                        std::move(payload_from_controller_fn),
79                        connection_handle,
80                        local_cid),
81       L2capWriteChannel(l2cap_channel_manager,
82                         connection_handle,
83                         AclTransportType::kLe,
84                         remote_cid) {}
85 
HandlePduFromController(pw::span<uint8_t> bframe)86 bool BasicL2capChannel::HandlePduFromController(pw::span<uint8_t> bframe) {
87   Result<emboss::BFrameWriter> bframe_view =
88       MakeEmbossWriter<emboss::BFrameWriter>(bframe);
89 
90   if (!bframe_view.ok()) {
91     // TODO: https://pwbug.dev/360929142 - Stop channel on error.
92     PW_LOG_ERROR("(CID: 0x%X) Received invalid B-frame. So will drop.",
93                  local_cid());
94   } else {
95     SendPayloadFromControllerToClient(
96         span(bframe_view->payload().BackingStorage().data(),
97              bframe_view->payload().SizeInBytes()));
98   }
99   return true;
100 }
101 
HandlePduFromHost(pw::span<uint8_t>)102 bool BasicL2capChannel::HandlePduFromHost(pw::span<uint8_t>) {
103   // Always forward to controller.
104   return false;
105 }
106 
107 }  // namespace pw::bluetooth::proxy
108