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/channel.h"
16
17 #include <cpp-string/string_printf.h>
18
19 #include <memory>
20 #include <utility>
21
22 #include "lib/fit/result.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
26 #include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
27 #include "pw_bluetooth_sapphire/internal/host/l2cap/basic_mode_rx_engine.h"
28 #include "pw_bluetooth_sapphire/internal/host/l2cap/basic_mode_tx_engine.h"
29 #include "pw_bluetooth_sapphire/internal/host/l2cap/credit_based_flow_control_rx_engine.h"
30 #include "pw_bluetooth_sapphire/internal/host/l2cap/credit_based_flow_control_tx_engine.h"
31 #include "pw_bluetooth_sapphire/internal/host/l2cap/enhanced_retransmission_mode_engines.h"
32 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
33 #include "pw_bluetooth_sapphire/internal/host/l2cap/logical_link.h"
34 #include "pw_bluetooth_sapphire/internal/host/transport/link_type.h"
35
36 namespace bt::l2cap {
37
38 namespace android_hci = bt::hci_spec::vendor::android;
39 using pw::bluetooth::AclPriority;
40
Channel(ChannelId id,ChannelId remote_id,bt::LinkType link_type,hci_spec::ConnectionHandle link_handle,ChannelInfo info,uint16_t max_tx_queued)41 Channel::Channel(ChannelId id,
42 ChannelId remote_id,
43 bt::LinkType link_type,
44 hci_spec::ConnectionHandle link_handle,
45 ChannelInfo info,
46 uint16_t max_tx_queued)
47 : WeakSelf(this),
48 id_(id),
49 remote_id_(remote_id),
50 link_type_(link_type),
51 link_handle_(link_handle),
52 info_(info),
53 max_tx_queued_(max_tx_queued),
54 requested_acl_priority_(AclPriority::kNormal) {
55 PW_DCHECK(id_);
56 PW_DCHECK(link_type_ == bt::LinkType::kLE ||
57 link_type_ == bt::LinkType::kACL);
58 }
59
60 namespace internal {
61
62 namespace {
63
64 constexpr const char* kInspectPsmPropertyName = "psm";
65 constexpr const char* kInspectLocalIdPropertyName = "local_id";
66 constexpr const char* kInspectRemoteIdPropertyName = "remote_id";
67 constexpr const char* kInspectDroppedPacketsPropertyName = "dropped_packets";
68
69 } // namespace
70
CreateFixedChannel(pw::async::Dispatcher & dispatcher,ChannelId id,internal::LogicalLinkWeakPtr link,hci::CommandChannel::WeakPtr cmd_channel,uint16_t max_acl_payload_size,A2dpOffloadManager & a2dp_offload_manager,uint16_t max_tx_queued)71 std::unique_ptr<ChannelImpl> ChannelImpl::CreateFixedChannel(
72 pw::async::Dispatcher& dispatcher,
73 ChannelId id,
74 internal::LogicalLinkWeakPtr link,
75 hci::CommandChannel::WeakPtr cmd_channel,
76 uint16_t max_acl_payload_size,
77 A2dpOffloadManager& a2dp_offload_manager,
78 uint16_t max_tx_queued) {
79 // A fixed channel's endpoints have the same local and remote identifiers.
80 // Setting the ChannelInfo MTU to kMaxMTU effectively cancels any L2CAP-level
81 // MTU enforcement for services which operate over fixed channels. Such
82 // services often define minimum MTU values in their specification, so they
83 // are required to respect these MTUs internally by:
84 // 1.) never sending packets larger than their spec-defined MTU.
85 // 2.) handling inbound PDUs which are larger than their spec-defined MTU
86 // appropriately.
87 return std::unique_ptr<ChannelImpl>(
88 new ChannelImpl(dispatcher,
89 id,
90 id,
91 link,
92 ChannelInfo::MakeBasicMode(kMaxMTU, kMaxMTU),
93 std::move(cmd_channel),
94 max_acl_payload_size,
95 a2dp_offload_manager,
96 max_tx_queued));
97 }
98
CreateDynamicChannel(pw::async::Dispatcher & dispatcher,ChannelId id,ChannelId peer_id,internal::LogicalLinkWeakPtr link,ChannelInfo info,hci::CommandChannel::WeakPtr cmd_channel,uint16_t max_acl_payload_size,A2dpOffloadManager & a2dp_offload_manager,uint16_t max_tx_queued)99 std::unique_ptr<ChannelImpl> ChannelImpl::CreateDynamicChannel(
100 pw::async::Dispatcher& dispatcher,
101 ChannelId id,
102 ChannelId peer_id,
103 internal::LogicalLinkWeakPtr link,
104 ChannelInfo info,
105 hci::CommandChannel::WeakPtr cmd_channel,
106 uint16_t max_acl_payload_size,
107 A2dpOffloadManager& a2dp_offload_manager,
108 uint16_t max_tx_queued) {
109 return std::unique_ptr<ChannelImpl>(new ChannelImpl(dispatcher,
110 id,
111 peer_id,
112 link,
113 info,
114 std::move(cmd_channel),
115 max_acl_payload_size,
116 a2dp_offload_manager,
117 max_tx_queued));
118 }
119
ChannelImpl(pw::async::Dispatcher & dispatcher,ChannelId id,ChannelId remote_id,internal::LogicalLinkWeakPtr link,ChannelInfo info,hci::CommandChannel::WeakPtr cmd_channel,uint16_t max_acl_payload_size,A2dpOffloadManager & a2dp_offload_manager,uint16_t max_tx_queued)120 ChannelImpl::ChannelImpl(pw::async::Dispatcher& dispatcher,
121 ChannelId id,
122 ChannelId remote_id,
123 internal::LogicalLinkWeakPtr link,
124 ChannelInfo info,
125 hci::CommandChannel::WeakPtr cmd_channel,
126 uint16_t max_acl_payload_size,
127 A2dpOffloadManager& a2dp_offload_manager,
128 uint16_t max_tx_queued)
129 : Channel(id, remote_id, link->type(), link->handle(), info, max_tx_queued),
130 pw_dispatcher_(dispatcher),
131 active_(false),
132 link_(link),
133 cmd_channel_(std::move(cmd_channel)),
134 fragmenter_(link->handle(), max_acl_payload_size),
135 a2dp_offload_manager_(a2dp_offload_manager),
136 weak_self_(this) {
137 PW_CHECK(link_.is_alive());
138 PW_CHECK(
139 info_.mode == RetransmissionAndFlowControlMode::kBasic ||
140 info_.mode ==
141 RetransmissionAndFlowControlMode::kEnhancedRetransmission ||
142 info.mode == CreditBasedFlowControlMode::kLeCreditBasedFlowControl,
143 "Channel constructed with unsupported mode: %s\n",
144 AnyChannelModeToString(info_.mode).c_str());
145
146 auto connection_failure_cb = [link] {
147 if (link.is_alive()) {
148 // |link| is expected to ignore this call if it has been closed.
149 link->SignalError();
150 }
151 };
152
153 if (info_.mode == RetransmissionAndFlowControlMode::kBasic) {
154 rx_engine_ = std::make_unique<BasicModeRxEngine>();
155 tx_engine_ =
156 std::make_unique<BasicModeTxEngine>(id, max_tx_sdu_size(), *this);
157 } else if (std::holds_alternative<CreditBasedFlowControlMode>(info_.mode)) {
158 PW_CHECK(info_.remote_initial_credits.has_value());
159 auto mode = std::get<CreditBasedFlowControlMode>(info_.mode);
160 rx_engine_ = std::make_unique<CreditBasedFlowControlRxEngine>(
161 std::move(connection_failure_cb));
162 tx_engine_ = std::make_unique<CreditBasedFlowControlTxEngine>(
163 id,
164 max_tx_sdu_size(),
165 *this,
166 mode,
167 info_.max_tx_pdu_payload_size,
168 *info_.remote_initial_credits);
169 } else {
170 std::tie(rx_engine_, tx_engine_) =
171 MakeLinkedEnhancedRetransmissionModeEngines(
172 id,
173 max_tx_sdu_size(),
174 info_.max_transmissions,
175 info_.n_frames_in_tx_window,
176 *this,
177 std::move(connection_failure_cb),
178 pw_dispatcher_);
179 }
180 }
181
~ChannelImpl()182 ChannelImpl::~ChannelImpl() {
183 size_t removed_count = this->pending_tx_sdus_.size();
184 if (removed_count > 0) {
185 bt_log(TRACE,
186 "hci",
187 "packets dropped (count: %zu) due to channel destruction (link: "
188 "%#.4x, id: %#.4x)",
189 removed_count,
190 link_handle(),
191 id());
192 }
193 }
194
security()195 const sm::SecurityProperties ChannelImpl::security() {
196 if (link_.is_alive()) {
197 return link_->security();
198 }
199 return sm::SecurityProperties();
200 }
201
Activate(RxCallback rx_callback,ClosedCallback closed_callback)202 bool ChannelImpl::Activate(RxCallback rx_callback,
203 ClosedCallback closed_callback) {
204 PW_CHECK(rx_callback);
205 PW_CHECK(closed_callback);
206
207 // Activating on a closed link has no effect. We also clear this on
208 // deactivation to prevent a channel from being activated more than once.
209 if (!link_.is_alive())
210 return false;
211
212 PW_CHECK(!active_);
213 active_ = true;
214 rx_cb_ = std::move(rx_callback);
215 closed_cb_ = std::move(closed_callback);
216
217 // Route the buffered packets.
218 if (!pending_rx_sdus_.empty()) {
219 TRACE_DURATION("bluetooth", "ChannelImpl::Activate pending drain");
220 // Channel may be destroyed in rx_cb_, so we need to check self after
221 // calling rx_cb_.
222 auto self = GetWeakPtr();
223 auto pending = std::move(pending_rx_sdus_);
224 while (self.is_alive() && !pending.empty()) {
225 TRACE_FLOW_END(
226 "bluetooth", "ChannelImpl::HandleRxPdu queued", pending.size());
227 rx_cb_(std::move(pending.front()));
228 pending.pop();
229 }
230 }
231
232 return true;
233 }
234
Deactivate()235 void ChannelImpl::Deactivate() {
236 bt_log(TRACE,
237 "l2cap",
238 "deactivating channel (link: %#.4x, id: %#.4x)",
239 link_handle(),
240 id());
241
242 // De-activating on a closed link has no effect.
243 if (!link_.is_alive() || !active_) {
244 link_ = internal::LogicalLinkWeakPtr();
245 return;
246 }
247
248 auto link = link_;
249
250 CleanUp();
251
252 // |link| is expected to ignore this call if it has been closed.
253 link->RemoveChannel(this, /*removed_cb=*/[] {});
254 }
255
SignalLinkError()256 void ChannelImpl::SignalLinkError() {
257 // Cannot signal an error on a closed or deactivated link.
258 if (!link_.is_alive() || !active_)
259 return;
260
261 // |link_| is expected to ignore this call if it has been closed.
262 link_->SignalError();
263 }
264
Send(ByteBufferPtr sdu)265 bool ChannelImpl::Send(ByteBufferPtr sdu) {
266 PW_DCHECK(sdu);
267
268 TRACE_DURATION(
269 "bluetooth", "l2cap:send", "handle", link_->handle(), "id", id());
270
271 if (!link_.is_alive()) {
272 bt_log(ERROR, "l2cap", "cannot send SDU on a closed link");
273 return false;
274 }
275
276 if (!active_) {
277 bt_log(INFO, "l2cap", "not sending SDU on an inactive channel");
278 return false;
279 }
280
281 // Cap the Tx SDU queue to |max_tx_queued|.
282 if (pending_tx_sdus_.size() > max_tx_queued()) {
283 return false;
284 }
285
286 pending_tx_sdus_.push(std::move(sdu));
287 tx_engine_->NotifySduQueued();
288 return true;
289 }
290
GetNextOutboundPacket()291 std::unique_ptr<hci::ACLDataPacket> ChannelImpl::GetNextOutboundPacket() {
292 // Channel's next packet is a starting fragment
293 if (!HasFragments() && HasPDUs()) {
294 // B-frames for Basic Mode contain only an "Information payload" (v5.0 Vol
295 // 3, Part A, Sec 3.1)
296 FrameCheckSequenceOption fcs_option =
297 info().mode == RetransmissionAndFlowControlMode::kEnhancedRetransmission
298 ? FrameCheckSequenceOption::kIncludeFcs
299 : FrameCheckSequenceOption::kNoFcs;
300 // Get new PDU and release fragments
301 auto pdu =
302 fragmenter_.BuildFrame(remote_id(),
303 *pending_tx_pdus_.front(),
304 fcs_option,
305 /*flushable=*/info().flush_timeout.has_value());
306 pending_tx_fragments_ = pdu.ReleaseFragments();
307 pending_tx_pdus_.pop();
308 }
309
310 // Send next packet if it exists
311 std::unique_ptr<hci::ACLDataPacket> fragment = nullptr;
312 if (HasFragments()) {
313 fragment = std::move(pending_tx_fragments_.front());
314 pending_tx_fragments_.pop_front();
315 }
316 return fragment;
317 }
318
UpgradeSecurity(sm::SecurityLevel level,sm::ResultFunction<> callback)319 void ChannelImpl::UpgradeSecurity(sm::SecurityLevel level,
320 sm::ResultFunction<> callback) {
321 PW_CHECK(callback);
322
323 if (!link_.is_alive() || !active_) {
324 bt_log(DEBUG, "l2cap", "Ignoring security request on inactive channel");
325 return;
326 }
327
328 link_->UpgradeSecurity(level, std::move(callback));
329 }
330
RequestAclPriority(AclPriority priority,fit::callback<void (fit::result<fit::failed>)> callback)331 void ChannelImpl::RequestAclPriority(
332 AclPriority priority,
333 fit::callback<void(fit::result<fit::failed>)> callback) {
334 if (!link_.is_alive() || !active_) {
335 bt_log(DEBUG, "l2cap", "Ignoring ACL priority request on inactive channel");
336 callback(fit::failed());
337 return;
338 }
339
340 // Callback is only called after checking that the weak pointer passed is
341 // alive, so using this in lambda is safe.
342 link_->RequestAclPriority(
343 GetWeakPtr(),
344 priority,
345 [self = GetWeakPtr(), this, priority, cb = std::move(callback)](
346 auto result) mutable {
347 if (self.is_alive() && result.is_ok()) {
348 requested_acl_priority_ = priority;
349 }
350 cb(result);
351 });
352 }
353
SetBrEdrAutomaticFlushTimeout(pw::chrono::SystemClock::duration flush_timeout,hci::ResultCallback<> callback)354 void ChannelImpl::SetBrEdrAutomaticFlushTimeout(
355 pw::chrono::SystemClock::duration flush_timeout,
356 hci::ResultCallback<> callback) {
357 PW_CHECK(link_type_ == bt::LinkType::kACL);
358
359 // Channel may be inactive if this method is called before activation.
360 if (!link_.is_alive()) {
361 bt_log(DEBUG, "l2cap", "Ignoring %s on closed channel", __FUNCTION__);
362 callback(ToResult(pw::bluetooth::emboss::StatusCode::COMMAND_DISALLOWED));
363 return;
364 }
365
366 auto cb_wrapper = [self = GetWeakPtr(),
367 this,
368 cb = std::move(callback),
369 flush_timeout](auto result) mutable {
370 if (!self.is_alive()) {
371 cb(ToResult(pw::bluetooth::emboss::StatusCode::UNSPECIFIED_ERROR));
372 return;
373 }
374
375 if (result.is_ok()) {
376 info_.flush_timeout = flush_timeout;
377 }
378
379 cb(result);
380 };
381
382 link_->SetBrEdrAutomaticFlushTimeout(flush_timeout, std::move(cb_wrapper));
383 }
384
AttachInspect(inspect::Node & parent,std::string name)385 void ChannelImpl::AttachInspect(inspect::Node& parent, std::string name) {
386 inspect_.node = parent.CreateChild(name);
387 if (info_.psm) {
388 inspect_.psm = inspect_.node.CreateString(kInspectPsmPropertyName,
389 PsmToString(info_.psm.value()));
390 }
391 inspect_.local_id = inspect_.node.CreateString(
392 kInspectLocalIdPropertyName,
393 bt_lib_cpp_string::StringPrintf("%#.4x", id()));
394 inspect_.remote_id = inspect_.node.CreateString(
395 kInspectRemoteIdPropertyName,
396 bt_lib_cpp_string::StringPrintf("%#.4x", remote_id()));
397
398 if (dropped_packets) {
399 inspect_.dropped_packets = inspect_.node.CreateUint(
400 kInspectDroppedPacketsPropertyName, dropped_packets);
401 }
402 }
403
StartA2dpOffload(const A2dpOffloadManager::Configuration & config,hci::ResultCallback<> callback)404 void ChannelImpl::StartA2dpOffload(
405 const A2dpOffloadManager::Configuration& config,
406 hci::ResultCallback<> callback) {
407 a2dp_offload_manager_.StartA2dpOffload(config,
408 id(),
409 remote_id(),
410 link_handle(),
411 max_tx_sdu_size(),
412 std::move(callback));
413 }
414
StopA2dpOffload(hci::ResultCallback<> callback)415 void ChannelImpl::StopA2dpOffload(hci::ResultCallback<> callback) {
416 a2dp_offload_manager_.RequestStopA2dpOffload(
417 id(), link_handle(), std::move(callback));
418 }
419
OnClosed()420 void ChannelImpl::OnClosed() {
421 bt_log(TRACE,
422 "l2cap",
423 "channel closed (link: %#.4x, id: %#.4x)",
424 link_handle(),
425 id());
426
427 if (!link_.is_alive() || !active_) {
428 link_ = internal::LogicalLinkWeakPtr();
429 return;
430 }
431
432 PW_CHECK(closed_cb_);
433 auto closed_cb = std::move(closed_cb_);
434
435 CleanUp();
436
437 closed_cb();
438 }
439
HandleRxPdu(PDU && pdu)440 void ChannelImpl::HandleRxPdu(PDU&& pdu) {
441 TRACE_DURATION("bluetooth",
442 "ChannelImpl::HandleRxPdu",
443 "handle",
444 link_->handle(),
445 "channel_id",
446 id_);
447
448 // link_ may be nullptr if a pdu is received after the channel has been
449 // deactivated but before LogicalLink::RemoveChannel has been dispatched
450 if (!link_.is_alive()) {
451 bt_log(TRACE, "l2cap", "ignoring pdu on deactivated channel");
452 return;
453 }
454
455 PW_CHECK(rx_engine_);
456
457 ByteBufferPtr sdu = rx_engine_->ProcessPdu(std::move(pdu));
458 if (!sdu) {
459 // The PDU may have been invalid, out-of-sequence, or part of a segmented
460 // SDU.
461 // * If invalid, we drop the PDU (per Core Spec Ver 5, Vol 3, Part A,
462 // Secs. 3.3.6 and/or 3.3.7).
463 // * If out-of-sequence or part of a segmented SDU, we expect that some
464 // later call to ProcessPdu() will return us an SDU containing this
465 // PDU's data.
466 return;
467 }
468
469 // Buffer the packets if the channel hasn't been activated.
470 if (!active_) {
471 pending_rx_sdus_.emplace(std::move(sdu));
472 // Tracing: we assume pending_rx_sdus_ is only filled once and use the
473 // length of queue for trace ids.
474 TRACE_FLOW_BEGIN("bluetooth",
475 "ChannelImpl::HandleRxPdu queued",
476 pending_rx_sdus_.size());
477 return;
478 }
479
480 PW_CHECK(rx_cb_);
481 {
482 TRACE_DURATION("bluetooth", "ChannelImpl::HandleRxPdu callback");
483 rx_cb_(std::move(sdu));
484 }
485 }
486
CleanUp()487 void ChannelImpl::CleanUp() {
488 RequestAclPriority(AclPriority::kNormal, [](auto result) {
489 if (result.is_error()) {
490 bt_log(WARN, "l2cap", "Resetting ACL priority on channel closed failed");
491 }
492 });
493
494 a2dp_offload_manager_.RequestStopA2dpOffload(
495 id(), link_handle(), [](auto result) {
496 if (result.is_error()) {
497 bt_log(WARN,
498 "l2cap",
499 "Stopping A2DP offloading on channel closed failed: %s",
500 bt_str(result));
501 }
502 });
503
504 active_ = false;
505 link_ = internal::LogicalLinkWeakPtr();
506 rx_cb_ = nullptr;
507 closed_cb_ = nullptr;
508 rx_engine_ = nullptr;
509 tx_engine_ = nullptr;
510 }
511
SendFrame(ByteBufferPtr pdu)512 void ChannelImpl::SendFrame(ByteBufferPtr pdu) {
513 if (!link_.is_alive() || !active_) {
514 bt_log(DEBUG,
515 "l2cap",
516 "dropping ACL packet for inactive connection (handle: %#.4x)",
517 link_->handle());
518 return;
519 }
520
521 pending_tx_pdus_.emplace(std::move(pdu));
522
523 // Ensure that |pending_tx_pdus_| does not exceed its maximum queue size
524 if (pending_tx_pdus_.size() > max_tx_queued()) {
525 if (dropped_packets % 100 == 0) {
526 bt_log(DEBUG,
527 "l2cap",
528 "Queued packets (%zu) exceeds maximum (%u). "
529 "Dropping oldest ACL packet (handle: %#.4x)",
530 pending_tx_pdus_.size(),
531 max_tx_queued(),
532 link_->handle());
533
534 inspect_.dropped_packets.Set(dropped_packets);
535 }
536 dropped_packets += 1;
537
538 pending_tx_pdus_.pop(); // Remove the oldest (aka first) element
539 }
540
541 // Notify LogicalLink that a packet is available. This is only necessary for
542 // the first packet of an empty queue (flow control will poll this connection
543 // otherwise).
544 if (pending_tx_pdus_.size() == 1u) {
545 link_->OnOutboundPacketAvailable();
546 }
547 }
548
GetNextQueuedSdu()549 std::optional<ByteBufferPtr> ChannelImpl::GetNextQueuedSdu() {
550 if (pending_tx_sdus_.empty())
551 return std::nullopt;
552 ByteBufferPtr next_sdu = std::move(pending_tx_sdus_.front());
553 pending_tx_sdus_.pop();
554 return next_sdu;
555 }
556
557 } // namespace internal
558 } // namespace bt::l2cap
559