xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/fake_channel.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/l2cap/fake_channel.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/common/host_error.h"
18 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
19 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
20 
21 namespace bt::l2cap::testing {
22 
FakeChannel(ChannelId id,ChannelId remote_id,hci_spec::ConnectionHandle handle,bt::LinkType link_type,ChannelInfo info,uint16_t max_tx_queued)23 FakeChannel::FakeChannel(ChannelId id,
24                          ChannelId remote_id,
25                          hci_spec::ConnectionHandle handle,
26                          bt::LinkType link_type,
27                          ChannelInfo info,
28                          uint16_t max_tx_queued)
29     : Channel(id, remote_id, link_type, handle, info, max_tx_queued),
30       handle_(handle),
31       fragmenter_(handle),
32       activate_fails_(false),
33       link_error_(false),
34       acl_priority_fails_(false),
35       weak_fake_chan_(this) {}
36 
Receive(const ByteBuffer & data)37 void FakeChannel::Receive(const ByteBuffer& data) {
38   auto pdu =
39       fragmenter_.BuildFrame(id(), data, FrameCheckSequenceOption::kNoFcs);
40   auto sdu = std::make_unique<DynamicByteBuffer>(pdu.length());
41   pdu.Copy(sdu.get());
42   if (rx_cb_) {
43     rx_cb_(std::move(sdu));
44   } else {
45     pending_rx_sdus_.push(std::move(sdu));
46   }
47 }
48 
SetSendCallback(SendCallback callback)49 void FakeChannel::SetSendCallback(SendCallback callback) {
50   send_cb_ = std::move(callback);
51 }
52 
SetSendCallback(SendCallback callback,pw::async::Dispatcher & dispatcher)53 void FakeChannel::SetSendCallback(SendCallback callback,
54                                   pw::async::Dispatcher& dispatcher) {
55   SetSendCallback(std::move(callback));
56   send_dispatcher_.emplace(dispatcher);
57 }
58 
SetLinkErrorCallback(LinkErrorCallback callback)59 void FakeChannel::SetLinkErrorCallback(LinkErrorCallback callback) {
60   link_err_cb_ = std::move(callback);
61 }
62 
SetSecurityCallback(SecurityUpgradeCallback callback,pw::async::Dispatcher & dispatcher)63 void FakeChannel::SetSecurityCallback(SecurityUpgradeCallback callback,
64                                       pw::async::Dispatcher& dispatcher) {
65   security_cb_ = std::move(callback);
66   security_dispatcher_.emplace(dispatcher);
67 }
68 
Close()69 void FakeChannel::Close() {
70   if (closed_cb_)
71     closed_cb_();
72 }
73 
Activate(RxCallback rx_callback,ClosedCallback closed_callback)74 bool FakeChannel::Activate(RxCallback rx_callback,
75                            ClosedCallback closed_callback) {
76   PW_DCHECK(rx_callback);
77   PW_DCHECK(closed_callback);
78   PW_DCHECK(!rx_cb_);
79   PW_DCHECK(!closed_cb_);
80 
81   if (activate_fails_)
82     return false;
83 
84   closed_cb_ = std::move(closed_callback);
85   rx_cb_ = std::move(rx_callback);
86 
87   while (!pending_rx_sdus_.empty()) {
88     rx_cb_(std::move(pending_rx_sdus_.front()));
89     pending_rx_sdus_.pop();
90   }
91 
92   return true;
93 }
94 
Deactivate()95 void FakeChannel::Deactivate() {
96   closed_cb_ = {};
97   rx_cb_ = {};
98 }
99 
SignalLinkError()100 void FakeChannel::SignalLinkError() {
101   if (link_error_) {
102     return;
103   }
104   link_error_ = true;
105 
106   if (link_err_cb_) {
107     link_err_cb_();
108   }
109 }
110 
Send(ByteBufferPtr sdu)111 bool FakeChannel::Send(ByteBufferPtr sdu) {
112   PW_DCHECK(sdu);
113 
114   if (!send_cb_)
115     return false;
116 
117   if (sdu->size() > max_tx_sdu_size()) {
118     bt_log(ERROR,
119            "l2cap",
120            "Dropping oversized SDU (sdu->size()=%zu, max_tx_sdu_size()=%u)",
121            sdu->size(),
122            max_tx_sdu_size());
123     return false;
124   }
125 
126   if (send_dispatcher_) {
127     (void)send_dispatcher_->Post(
128         [cb = send_cb_.share(), sdu = std::move(sdu)](
129             pw::async::Context /*ctx*/, pw::Status status) mutable {
130           if (status.ok()) {
131             cb(std::move(sdu));
132           }
133         });
134   } else {
135     send_cb_(std::move(sdu));
136   }
137 
138   return true;
139 }
140 
UpgradeSecurity(sm::SecurityLevel level,sm::ResultFunction<> callback)141 void FakeChannel::UpgradeSecurity(sm::SecurityLevel level,
142                                   sm::ResultFunction<> callback) {
143   PW_CHECK(security_dispatcher_);
144   (void)security_dispatcher_->Post(
145       [cb = std::move(callback),
146        f = security_cb_.share(),
147        handle = handle_,
148        level](pw::async::Context /*ctx*/, pw::Status status) mutable {
149         if (status.ok()) {
150           f(handle, level, std::move(cb));
151         }
152       });
153 }
154 
RequestAclPriority(pw::bluetooth::AclPriority priority,fit::callback<void (fit::result<fit::failed>)> cb)155 void FakeChannel::RequestAclPriority(
156     pw::bluetooth::AclPriority priority,
157     fit::callback<void(fit::result<fit::failed>)> cb) {
158   if (acl_priority_fails_) {
159     cb(fit::failed());
160     return;
161   }
162   requested_acl_priority_ = priority;
163   cb(fit::ok());
164 }
165 
SetBrEdrAutomaticFlushTimeout(pw::chrono::SystemClock::duration flush_timeout,hci::ResultCallback<> callback)166 void FakeChannel::SetBrEdrAutomaticFlushTimeout(
167     pw::chrono::SystemClock::duration flush_timeout,
168     hci::ResultCallback<> callback) {
169   if (!flush_timeout_succeeds_) {
170     callback(ToResult(pw::bluetooth::emboss::StatusCode::UNSPECIFIED_ERROR));
171     return;
172   }
173   info_.flush_timeout = flush_timeout;
174   callback(fit::ok());
175 }
176 
StartA2dpOffload(const A2dpOffloadManager::Configuration &,hci::ResultCallback<> callback)177 void FakeChannel::StartA2dpOffload(const A2dpOffloadManager::Configuration&,
178                                    hci::ResultCallback<> callback) {
179   if (a2dp_offload_error_.has_value()) {
180     callback(ToResult(a2dp_offload_error_.value()));
181     audio_offloading_status_ = A2dpOffloadStatus::kStopped;
182     return;
183   }
184   audio_offloading_status_ = A2dpOffloadStatus::kStarted;
185   callback(fit::ok());
186 }
187 
StopA2dpOffload(hci::ResultCallback<> callback)188 void FakeChannel::StopA2dpOffload(hci::ResultCallback<> callback) {
189   if (a2dp_offload_error_.has_value()) {
190     callback(ToResult(a2dp_offload_error_.value()));
191     return;
192   }
193   audio_offloading_status_ = A2dpOffloadStatus::kStopped;
194   callback(fit::ok());
195 }
196 
197 }  // namespace bt::l2cap::testing
198