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/logical_link.h"
16
17 #include <cpp-string/string_printf.h>
18 #include <pw_assert/check.h>
19
20 #include <cinttypes>
21 #include <functional>
22 #include <memory>
23
24 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/trace.h"
26 #include "pw_bluetooth_sapphire/internal/host/l2cap/bredr_dynamic_channel.h"
27 #include "pw_bluetooth_sapphire/internal/host/l2cap/bredr_signaling_channel.h"
28 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h"
29 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
30 #include "pw_bluetooth_sapphire/internal/host/l2cap/le_dynamic_channel.h"
31 #include "pw_bluetooth_sapphire/internal/host/l2cap/le_signaling_channel.h"
32 #include "pw_bluetooth_sapphire/internal/host/transport/link_type.h"
33 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
34
35 namespace bt::l2cap::internal {
36
37 using pw::bluetooth::AclPriority;
38
39 namespace {
40
41 const char* kInspectHandlePropertyName = "handle";
42 const char* kInspectLinkTypePropertyName = "link_type";
43 const char* kInspectChannelsNodeName = "channels";
44 const char* kInspectChannelNodePrefix = "channel_";
45 const char* kInspectFlushTimeoutPropertyName = "flush_timeout_ms";
46
IsValidLEFixedChannel(ChannelId id)47 constexpr bool IsValidLEFixedChannel(ChannelId id) {
48 switch (id) {
49 case kATTChannelId:
50 case kLESignalingChannelId:
51 case kLESMPChannelId:
52 return true;
53 default:
54 break;
55 }
56 return false;
57 }
58
IsValidBREDRFixedChannel(ChannelId id)59 constexpr bool IsValidBREDRFixedChannel(ChannelId id) {
60 switch (id) {
61 case kSignalingChannelId:
62 case kConnectionlessChannelId:
63 case kSMPChannelId:
64 return true;
65 default:
66 break;
67 }
68 return false;
69 }
70
FixedChannelsSupportedBitForChannelId(ChannelId channel_id)71 FixedChannelsSupported FixedChannelsSupportedBitForChannelId(
72 ChannelId channel_id) {
73 switch (channel_id) {
74 case kSignalingChannelId:
75 return kFixedChannelsSupportedBitSignaling;
76 case kConnectionlessChannelId:
77 return kFixedChannelsSupportedBitConnectionless;
78 case kSMPChannelId:
79 return kFixedChannelsSupportedBitSM;
80 default:
81 return 0;
82 }
83 }
84
85 } // namespace
86
LogicalLink(hci_spec::ConnectionHandle handle,bt::LinkType type,pw::bluetooth::emboss::ConnectionRole role,uint16_t max_acl_payload_size,QueryServiceCallback query_service_cb,hci::AclDataChannel * acl_data_channel,hci::CommandChannel * cmd_channel,bool random_channel_ids,A2dpOffloadManager & a2dp_offload_manager,pw::async::Dispatcher & dispatcher)87 LogicalLink::LogicalLink(hci_spec::ConnectionHandle handle,
88 bt::LinkType type,
89 pw::bluetooth::emboss::ConnectionRole role,
90 uint16_t max_acl_payload_size,
91 QueryServiceCallback query_service_cb,
92 hci::AclDataChannel* acl_data_channel,
93 hci::CommandChannel* cmd_channel,
94 bool random_channel_ids,
95 A2dpOffloadManager& a2dp_offload_manager,
96 pw::async::Dispatcher& dispatcher)
97 : pw_dispatcher_(dispatcher),
98 handle_(handle),
99 type_(type),
100 role_(role),
101 max_acl_payload_size_(max_acl_payload_size),
102 flush_timeout_(
103 pw::chrono::SystemClock::duration::max(), /*convert=*/
104 [](pw::chrono::SystemClock::duration f) {
105 return std::chrono::duration_cast<std::chrono::milliseconds>(f)
106 .count();
107 }),
108 closed_(false),
109 recombiner_(handle),
110 acl_data_channel_(acl_data_channel),
111 cmd_channel_(cmd_channel),
112 query_service_cb_(std::move(query_service_cb)),
113 a2dp_offload_manager_(a2dp_offload_manager),
114 weak_conn_interface_(this),
115 weak_self_(this) {
116 PW_CHECK(type_ == bt::LinkType::kLE || type_ == bt::LinkType::kACL);
117 PW_CHECK(acl_data_channel_);
118 PW_CHECK(cmd_channel_);
119 PW_CHECK(query_service_cb_);
120
121 // Allow packets to be sent on this link immediately.
122 acl_data_channel_->RegisterConnection(weak_conn_interface_.GetWeakPtr());
123
124 // Set up the signaling channel and dynamic channels.
125 if (type_ == bt::LinkType::kLE) {
126 signaling_channel_ = std::make_unique<LESignalingChannel>(
127 OpenFixedChannel(kLESignalingChannelId), role_, pw_dispatcher_);
128 dynamic_registry_ = std::make_unique<LeDynamicChannelRegistry>(
129 signaling_channel_.get(),
130 fit::bind_member<&LogicalLink::OnChannelDisconnectRequest>(this),
131 fit::bind_member<&LogicalLink::OnServiceRequest>(this),
132 random_channel_ids);
133
134 ServeConnectionParameterUpdateRequest();
135 } else {
136 signaling_channel_ = std::make_unique<BrEdrSignalingChannel>(
137 OpenFixedChannel(kSignalingChannelId), role_, pw_dispatcher_);
138 dynamic_registry_ = std::make_unique<BrEdrDynamicChannelRegistry>(
139 signaling_channel_.get(),
140 fit::bind_member<&LogicalLink::OnChannelDisconnectRequest>(this),
141 fit::bind_member<&LogicalLink::OnServiceRequest>(this),
142 random_channel_ids);
143
144 SendFixedChannelsSupportedInformationRequest();
145 }
146 }
147
~LogicalLink()148 LogicalLink::~LogicalLink() {
149 bt_log(DEBUG, "l2cap", "LogicalLink destroyed (handle: %#.4x)", handle_);
150 PW_CHECK(closed_);
151 }
152
OpenFixedChannel(ChannelId id)153 Channel::WeakPtr LogicalLink::OpenFixedChannel(ChannelId id) {
154 PW_DCHECK(!closed_);
155
156 TRACE_DURATION("bluetooth",
157 "LogicalLink::OpenFixedChannel",
158 "handle",
159 handle_,
160 "channel id",
161 id);
162
163 // We currently only support the pre-defined fixed-channels.
164 if (!AllowsFixedChannel(id)) {
165 bt_log(ERROR, "l2cap", "cannot open fixed channel with id %#.4x", id);
166 return Channel::WeakPtr();
167 }
168
169 auto iter = channels_.find(id);
170 if (iter != channels_.end()) {
171 bt_log(ERROR,
172 "l2cap",
173 "channel is already open! (id: %#.4x, handle: %#.4x)",
174 id,
175 handle_);
176 return Channel::WeakPtr();
177 }
178
179 std::unique_ptr<ChannelImpl> chan =
180 ChannelImpl::CreateFixedChannel(pw_dispatcher_,
181 id,
182 GetWeakPtr(),
183 cmd_channel_->AsWeakPtr(),
184 max_acl_payload_size_,
185 a2dp_offload_manager_);
186
187 auto pp_iter = pending_pdus_.find(id);
188 if (pp_iter != pending_pdus_.end()) {
189 for (auto& pdu : pp_iter->second) {
190 TRACE_FLOW_END(
191 "bluetooth", "LogicalLink::HandleRxPacket queued", pdu.trace_id());
192 chan->HandleRxPdu(std::move(pdu));
193 }
194 pending_pdus_.erase(pp_iter);
195 }
196
197 if (inspect_properties_.channels_node) {
198 chan->AttachInspect(inspect_properties_.channels_node,
199 inspect_properties_.channels_node.UniqueName(
200 kInspectChannelNodePrefix));
201 }
202
203 channels_[id] = std::move(chan);
204
205 // Reset round robin iterator
206 current_channel_ = channels_.begin();
207
208 return channels_[id]->GetWeakPtr();
209 }
210
OpenFixedChannelAsync(ChannelId channel_id,ChannelCallback callback)211 void LogicalLink::OpenFixedChannelAsync(ChannelId channel_id,
212 ChannelCallback callback) {
213 if (type_ == LinkType::kACL) {
214 if (fixed_channels_supported_callbacks_.count(channel_id) > 0) {
215 bt_log(ERROR,
216 "l2cap",
217 "fixed channel is already pending! (id: %#.4x, handle: %#.4x)",
218 channel_id,
219 handle_);
220 callback(Channel::WeakPtr());
221 return;
222 }
223
224 if (!fixed_channels_supported_.has_value()) {
225 fixed_channels_supported_callbacks_.emplace(
226 channel_id, [this, channel_id, cb = std::move(callback)]() mutable {
227 OpenFixedChannelAsync(channel_id, std::move(cb));
228 });
229 return;
230 }
231
232 bool channel_supported = *fixed_channels_supported_ &
233 FixedChannelsSupportedBitForChannelId(channel_id);
234
235 if (!channel_supported) {
236 bt_log(DEBUG,
237 "l2cap",
238 "tried to open fixed channel not supported by peer (id: %#.4x, "
239 "handle: %#.4x)",
240 channel_id,
241 handle_);
242 callback(Channel::WeakPtr());
243 return;
244 }
245 }
246
247 callback(OpenFixedChannel(channel_id));
248 }
249
OpenChannel(Psm psm,ChannelParameters params,ChannelCallback callback)250 void LogicalLink::OpenChannel(Psm psm,
251 ChannelParameters params,
252 ChannelCallback callback) {
253 PW_DCHECK(!closed_);
254 PW_DCHECK(dynamic_registry_);
255
256 auto create_channel =
257 [this, cb = std::move(callback)](const DynamicChannel* dyn_chan) mutable {
258 CompleteDynamicOpen(dyn_chan, std::move(cb));
259 };
260 dynamic_registry_->OpenOutbound(psm, params, std::move(create_channel));
261
262 // Reset round robin iterator
263 current_channel_ = channels_.begin();
264 }
265
HandleRxPacket(hci::ACLDataPacketPtr packet)266 void LogicalLink::HandleRxPacket(hci::ACLDataPacketPtr packet) {
267 PW_DCHECK(packet);
268 PW_DCHECK(!closed_);
269
270 TRACE_DURATION("bluetooth", "LogicalLink::HandleRxPacket", "handle", handle_);
271
272 // We do not support the Connectionless data channel, and the active broadcast
273 // flag can only be used on the connectionless channel. Drop packets that are
274 // broadcast.
275 if (packet->broadcast_flag() ==
276 hci_spec::ACLBroadcastFlag::kActivePeripheralBroadcast) {
277 bt_log(DEBUG, "l2cap", "Unsupported Broadcast Frame dropped");
278 return;
279 }
280
281 auto result = recombiner_.ConsumeFragment(std::move(packet));
282 if (result.frames_dropped) {
283 bt_log(TRACE, "l2cap", "Frame(s) dropped due to recombination error");
284 }
285
286 if (!result.pdu) {
287 // Either a partial fragment was received, which was buffered for
288 // recombination, or the packet was dropped.
289 return;
290 }
291
292 PW_DCHECK(result.pdu->is_valid());
293
294 uint16_t channel_id = result.pdu->channel_id();
295 auto iter = channels_.find(channel_id);
296 PendingPduMap::iterator pp_iter;
297
298 if (iter == channels_.end()) {
299 // Only buffer data for fixed channels. This prevents stale data that is
300 // intended for a closed dynamic channel from being delivered to a new
301 // channel that recycled the former's ID. The downside is that it's possible
302 // to lose any data that is received after a dynamic channel's connection
303 // request and before its completed configuration. This would require tricky
304 // additional state to track "pending open" channels here and it's not clear
305 // if that is necessary since hosts should not send data before a channel is
306 // first configured.
307 if (!AllowsFixedChannel(channel_id)) {
308 bt_log(WARN,
309 "l2cap",
310 "Dropping PDU for nonexistent dynamic channel %#.4x on link %#.4x",
311 channel_id,
312 handle_);
313 return;
314 }
315
316 // The packet was received on a channel for which no ChannelImpl currently
317 // exists. Buffer packets for the channel to receive when it gets created.
318 pp_iter = pending_pdus_.emplace(channel_id, std::list<PDU>()).first;
319 } else {
320 // A channel exists. |pp_iter| will be valid only if the drain task has not
321 // run yet (see LogicalLink::OpenFixedChannel()).
322 pp_iter = pending_pdus_.find(channel_id);
323 }
324
325 if (pp_iter != pending_pdus_.end()) {
326 result.pdu->set_trace_id(TRACE_NONCE());
327 TRACE_FLOW_BEGIN("bluetooth",
328 "LogicalLink::HandleRxPacket queued",
329 result.pdu->trace_id());
330
331 pp_iter->second.emplace_back(std::move(*result.pdu));
332
333 bt_log(TRACE,
334 "l2cap",
335 "PDU buffered (channel: %#.4x, ll: %#.4x)",
336 channel_id,
337 handle_);
338 return;
339 }
340
341 iter->second->HandleRxPdu(std::move(*result.pdu));
342 }
343
UpgradeSecurity(sm::SecurityLevel level,sm::ResultFunction<> callback)344 void LogicalLink::UpgradeSecurity(sm::SecurityLevel level,
345 sm::ResultFunction<> callback) {
346 PW_DCHECK(security_callback_);
347
348 if (closed_) {
349 bt_log(DEBUG, "l2cap", "Ignoring security request on closed link");
350 return;
351 }
352
353 // Report success If the link already has the expected security level.
354 if (level <= security().level()) {
355 callback(fit::ok());
356 return;
357 }
358
359 bt_log(DEBUG,
360 "l2cap",
361 "Security upgrade requested (level = %s)",
362 sm::LevelToString(level));
363 security_callback_(handle_, level, std::move(callback));
364 }
365
AssignSecurityProperties(const sm::SecurityProperties & security)366 void LogicalLink::AssignSecurityProperties(
367 const sm::SecurityProperties& security) {
368 if (closed_) {
369 bt_log(DEBUG, "l2cap", "Ignoring security request on closed link");
370 return;
371 }
372
373 bt_log(DEBUG,
374 "l2cap",
375 "Link security updated (handle: %#.4x): %s",
376 handle_,
377 security.ToString().c_str());
378
379 security_ = security;
380 }
381
HasAvailablePacket() const382 bool LogicalLink::HasAvailablePacket() const {
383 for (auto& [_, channel] : channels_) {
384 // TODO(fxbug.dev/42074553): Check HasSDUs() after transmission engines are
385 // refactored
386 if (channel->HasPDUs() || channel->HasFragments()) {
387 return true;
388 }
389 }
390 return false;
391 }
392
RoundRobinChannels()393 void LogicalLink::RoundRobinChannels() {
394 // Go through all channels in map
395 if (next(current_channel_) == channels_.end()) {
396 current_channel_ = channels_.begin();
397 } else {
398 current_channel_++;
399 }
400 }
401
IsNextPacketContinuingFragment() const402 bool LogicalLink::IsNextPacketContinuingFragment() const {
403 return current_pdus_channel_.is_alive() &&
404 current_pdus_channel_->HasFragments();
405 }
406
GetNextOutboundPacket()407 std::unique_ptr<hci::ACLDataPacket> LogicalLink::GetNextOutboundPacket() {
408 for (size_t i = 0; i < channels_.size(); i++) {
409 if (!IsNextPacketContinuingFragment()) {
410 current_pdus_channel_ = ChannelImpl::WeakPtr();
411
412 // Go to next channel to try and get next packet to send
413 RoundRobinChannels();
414
415 if (current_channel_->second->HasPDUs()) {
416 current_pdus_channel_ = current_channel_->second->GetWeakPtr();
417 }
418 }
419
420 if (current_pdus_channel_.is_alive()) {
421 // Next packet will either be a starting or continuing fragment
422 return current_pdus_channel_->GetNextOutboundPacket();
423 }
424 }
425 // All channels are empty
426 // This should never actually return a nullptr since we only call
427 // LogicalLink::GetNextOutboundPacket() when LogicalLink::HasAvailablePacket()
428 // is true
429 return nullptr;
430 }
431
OnOutboundPacketAvailable()432 void LogicalLink::OnOutboundPacketAvailable() {
433 acl_data_channel_->OnOutboundPacketAvailable();
434 }
435
set_error_callback(fit::closure callback)436 void LogicalLink::set_error_callback(fit::closure callback) {
437 link_error_cb_ = std::move(callback);
438 }
439
set_security_upgrade_callback(SecurityUpgradeCallback callback)440 void LogicalLink::set_security_upgrade_callback(
441 SecurityUpgradeCallback callback) {
442 security_callback_ = std::move(callback);
443 }
444
set_connection_parameter_update_callback(LEConnectionParameterUpdateCallback callback)445 void LogicalLink::set_connection_parameter_update_callback(
446 LEConnectionParameterUpdateCallback callback) {
447 connection_parameter_update_callback_ = std::move(callback);
448 }
449
AllowsFixedChannel(ChannelId id)450 bool LogicalLink::AllowsFixedChannel(ChannelId id) {
451 return (type_ == bt::LinkType::kLE) ? IsValidLEFixedChannel(id)
452 : IsValidBREDRFixedChannel(id);
453 }
454
RemoveChannel(Channel * chan,fit::closure removed_cb)455 void LogicalLink::RemoveChannel(Channel* chan, fit::closure removed_cb) {
456 PW_DCHECK(chan);
457
458 if (closed_) {
459 bt_log(DEBUG, "l2cap", "Ignore RemoveChannel() on closed link");
460 removed_cb();
461 return;
462 }
463
464 const ChannelId id = chan->id();
465 auto iter = channels_.find(id);
466 if (iter == channels_.end()) {
467 removed_cb();
468 return;
469 }
470
471 // Ignore if the found channel doesn't match the requested one (even though
472 // their IDs are the same).
473 if (iter->second.get() != chan) {
474 removed_cb();
475 return;
476 }
477
478 pending_pdus_.erase(id);
479 channels_.erase(iter);
480
481 // Reset round robin iterator
482 current_channel_ = channels_.begin();
483
484 // Disconnect the channel if it's a dynamic channel. This path is for local-
485 // initiated closures and does not invoke callbacks back to the channel user.
486 // TODO(armansito): Change this if statement into an assert when a registry
487 // gets created for LE channels.
488 if (dynamic_registry_) {
489 dynamic_registry_->CloseChannel(id, std::move(removed_cb));
490 return;
491 }
492
493 removed_cb();
494 }
495
SignalError()496 void LogicalLink::SignalError() {
497 if (closed_) {
498 bt_log(DEBUG, "l2cap", "Ignore SignalError() on closed link");
499 return;
500 }
501
502 bt_log(INFO,
503 "l2cap",
504 "Upper layer error on link %#.4x; closing all channels",
505 handle());
506
507 size_t num_channels_to_close = channels_.size();
508
509 if (signaling_channel_) {
510 PW_CHECK(channels_.count(kSignalingChannelId) ||
511 channels_.count(kLESignalingChannelId));
512 // There is no need to close the signaling channel.
513 num_channels_to_close--;
514 }
515
516 if (num_channels_to_close == 0) {
517 link_error_cb_();
518 return;
519 }
520
521 // num_channels_closing is shared across all callbacks.
522 fit::closure channel_removed_cb =
523 [this, channels_remaining = num_channels_to_close]() mutable {
524 channels_remaining--;
525 if (channels_remaining != 0) {
526 return;
527 }
528 bt_log(TRACE,
529 "l2cap",
530 "Channels on link %#.4x closed; passing error to lower layer",
531 handle());
532 // Invoking error callback may destroy this LogicalLink.
533 link_error_cb_();
534 };
535
536 for (auto channel_iter = channels_.begin();
537 channel_iter != channels_.end();) {
538 auto& [id, channel] = *channel_iter++;
539
540 // Do not close the signaling channel, as it is used to close the dynamic
541 // channels.
542 if (id == kSignalingChannelId || id == kLESignalingChannelId) {
543 continue;
544 }
545
546 // Signal the channel, as it did not request the closure.
547 channel->OnClosed();
548
549 // This erases from |channel_| and invalidates any iterator pointing to
550 // |channel|.
551 RemoveChannel(channel.get(), channel_removed_cb.share());
552 }
553 }
554
Close()555 void LogicalLink::Close() {
556 PW_DCHECK(!closed_);
557
558 closed_ = true;
559
560 acl_data_channel_->UnregisterConnection(handle_);
561
562 for (auto& iter : channels_) {
563 iter.second->OnClosed();
564 }
565 channels_.clear();
566 dynamic_registry_.reset();
567 }
568
569 std::optional<DynamicChannelRegistry::ServiceInfo>
OnServiceRequest(Psm psm)570 LogicalLink::OnServiceRequest(Psm psm) {
571 PW_DCHECK(!closed_);
572
573 // Query upper layer for a service handler attached to this PSM.
574 auto result = query_service_cb_(handle_, psm);
575 if (!result) {
576 return std::nullopt;
577 }
578
579 auto channel_cb = [this, chan_cb = std::move(result->channel_cb)](
580 const DynamicChannel* dyn_chan) mutable {
581 CompleteDynamicOpen(dyn_chan, std::move(chan_cb));
582 };
583 return DynamicChannelRegistry::ServiceInfo(result->channel_params,
584 std::move(channel_cb));
585 }
586
OnChannelDisconnectRequest(const DynamicChannel * dyn_chan)587 void LogicalLink::OnChannelDisconnectRequest(const DynamicChannel* dyn_chan) {
588 PW_DCHECK(dyn_chan);
589 PW_DCHECK(!closed_);
590
591 auto iter = channels_.find(dyn_chan->local_cid());
592 if (iter == channels_.end()) {
593 bt_log(WARN,
594 "l2cap",
595 "No ChannelImpl found for closing dynamic channel %#.4x",
596 dyn_chan->local_cid());
597 return;
598 }
599
600 ChannelImpl* channel = iter->second.get();
601 PW_DCHECK(channel->remote_id() == dyn_chan->remote_cid());
602
603 // Signal closure because this is a remote disconnection.
604 channel->OnClosed();
605 channels_.erase(iter);
606
607 // Reset round robin iterator
608 current_channel_ = channels_.begin();
609 }
610
CompleteDynamicOpen(const DynamicChannel * dyn_chan,ChannelCallback open_cb)611 void LogicalLink::CompleteDynamicOpen(const DynamicChannel* dyn_chan,
612 ChannelCallback open_cb) {
613 PW_DCHECK(!closed_);
614
615 if (!dyn_chan) {
616 open_cb(Channel::WeakPtr());
617 return;
618 }
619
620 const ChannelId local_cid = dyn_chan->local_cid();
621 const ChannelId remote_cid = dyn_chan->remote_cid();
622 bt_log(DEBUG,
623 "l2cap",
624 "Link %#.4x: Channel opened with ID %#.4x (remote ID: %#.4x, psm: %s)",
625 handle_,
626 local_cid,
627 remote_cid,
628 PsmToString(dyn_chan->psm()).c_str());
629
630 auto chan_info = dyn_chan->info();
631 // Extract preferred flush timeout to avoid creating channel with a flush
632 // timeout that hasn't been successfully configured yet.
633 auto preferred_flush_timeout = chan_info.flush_timeout;
634 chan_info.flush_timeout.reset();
635
636 std::unique_ptr<ChannelImpl> chan =
637 ChannelImpl::CreateDynamicChannel(pw_dispatcher_,
638 local_cid,
639 remote_cid,
640 GetWeakPtr(),
641 chan_info,
642 cmd_channel_->AsWeakPtr(),
643 max_acl_payload_size_,
644 a2dp_offload_manager_);
645 auto chan_weak = chan->GetWeakPtr();
646 channels_[local_cid] = std::move(chan);
647
648 if (inspect_properties_.channels_node) {
649 chan_weak->AttachInspect(inspect_properties_.channels_node,
650 inspect_properties_.channels_node.UniqueName(
651 kInspectChannelNodePrefix));
652 }
653
654 // If a flush timeout was requested for this channel, try to set it before
655 // returning the channel to the client to ensure outbound PDUs have correct
656 // flushable flag.
657 if (preferred_flush_timeout.has_value()) {
658 chan_weak->SetBrEdrAutomaticFlushTimeout(
659 preferred_flush_timeout.value(),
660 [cb = std::move(open_cb), chan_weak](auto /*result*/) {
661 cb(chan_weak);
662 });
663 return;
664 }
665
666 open_cb(std::move(chan_weak));
667 }
668
SendFixedChannelsSupportedInformationRequest()669 void LogicalLink::SendFixedChannelsSupportedInformationRequest() {
670 PW_CHECK(signaling_channel_);
671
672 BrEdrCommandHandler cmd_handler(signaling_channel_.get());
673 if (!cmd_handler.SendInformationRequest(
674 InformationType::kFixedChannelsSupported,
675 [self = GetWeakPtr()](auto& rsp) {
676 if (self.is_alive()) {
677 self->OnRxFixedChannelsSupportedInfoRsp(rsp);
678 }
679 })) {
680 bt_log(ERROR,
681 "l2cap",
682 "Failed to send Fixed Channels Supported Information Request");
683 return;
684 }
685
686 bt_log(TRACE, "l2cap", "Sent Fixed Channels Supported Information Request");
687 }
688
OnRxFixedChannelsSupportedInfoRsp(const BrEdrCommandHandler::InformationResponse & rsp)689 void LogicalLink::OnRxFixedChannelsSupportedInfoRsp(
690 const BrEdrCommandHandler::InformationResponse& rsp) {
691 if (rsp.status() == BrEdrCommandHandler::Status::kReject) {
692 bt_log(
693 TRACE,
694 "l2cap",
695 "Fixed Channels Supported Information Request rejected (reason %#.4hx)",
696 static_cast<unsigned short>(rsp.reject_reason()));
697 return;
698 }
699
700 if (rsp.result() == InformationResult::kNotSupported) {
701 bt_log(TRACE,
702 "l2cap",
703 "Received Fixed Channels Supported Information Response (result: "
704 "Not Supported)");
705 return;
706 }
707
708 if (rsp.result() != InformationResult::kSuccess) {
709 bt_log(TRACE,
710 "l2cap",
711 "Received Fixed Channels Supported Information Response (result: "
712 "%.4hx)",
713 static_cast<uint16_t>(rsp.result()));
714 return;
715 }
716
717 if (rsp.type() != InformationType::kFixedChannelsSupported) {
718 bt_log(TRACE,
719 "l2cap",
720 "Incorrect Fixed Channels Supported Information Response type "
721 "(type: %#.4hx)",
722 static_cast<unsigned short>(rsp.type()));
723 return;
724 }
725
726 bt_log(TRACE,
727 "l2cap",
728 "Received Fixed Channels Supported Information Response (mask: "
729 "%#016" PRIx64 ")",
730 rsp.fixed_channels());
731
732 fixed_channels_supported_ = rsp.fixed_channels();
733 auto callbacks = std::move(fixed_channels_supported_callbacks_);
734 fixed_channels_supported_callbacks_.clear();
735 for (auto& [_, cb] : callbacks) {
736 cb();
737 }
738 }
739
SendConnectionParameterUpdateRequest(hci_spec::LEPreferredConnectionParameters params,ConnectionParameterUpdateRequestCallback request_cb)740 void LogicalLink::SendConnectionParameterUpdateRequest(
741 hci_spec::LEPreferredConnectionParameters params,
742 ConnectionParameterUpdateRequestCallback request_cb) {
743 PW_CHECK(signaling_channel_);
744 PW_CHECK(type_ == bt::LinkType::kLE);
745 PW_CHECK(role_ == pw::bluetooth::emboss::ConnectionRole::PERIPHERAL);
746
747 LowEnergyCommandHandler cmd_handler(signaling_channel_.get());
748 cmd_handler.SendConnectionParameterUpdateRequest(
749 params.min_interval(),
750 params.max_interval(),
751 params.max_latency(),
752 params.supervision_timeout(),
753 [cb = std::move(request_cb)](
754 const LowEnergyCommandHandler::ConnectionParameterUpdateResponse&
755 rsp) mutable {
756 bool accepted = false;
757
758 if (rsp.status() != LowEnergyCommandHandler::Status::kSuccess) {
759 bt_log(TRACE,
760 "l2cap",
761 "LE Connection Parameter Update Request rejected (reason: "
762 "%#.4hx)",
763 static_cast<unsigned short>(rsp.reject_reason()));
764 } else {
765 accepted = rsp.result() == ConnectionParameterUpdateResult::kAccepted;
766 }
767 cb(accepted);
768 });
769 }
770
RequestAclPriority(Channel::WeakPtr channel,AclPriority priority,fit::callback<void (fit::result<fit::failed>)> callback)771 void LogicalLink::RequestAclPriority(
772 Channel::WeakPtr channel,
773 AclPriority priority,
774 fit::callback<void(fit::result<fit::failed>)> callback) {
775 PW_CHECK(channel.is_alive());
776 auto iter = channels_.find(channel->id());
777 PW_CHECK(iter != channels_.end());
778 pending_acl_requests_.push(
779 PendingAclRequest{std::move(channel), priority, std::move(callback)});
780 if (pending_acl_requests_.size() == 1) {
781 HandleNextAclPriorityRequest();
782 }
783 }
784
SetBrEdrAutomaticFlushTimeout(pw::chrono::SystemClock::duration flush_timeout,hci::ResultCallback<> callback)785 void LogicalLink::SetBrEdrAutomaticFlushTimeout(
786 pw::chrono::SystemClock::duration flush_timeout,
787 hci::ResultCallback<> callback) {
788 if (type_ != bt::LinkType::kACL) {
789 bt_log(
790 ERROR, "l2cap", "attempt to set flush timeout on non-ACL logical link");
791 callback(ToResult(
792 pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS));
793 return;
794 }
795
796 auto callback_wrapper = [self = GetWeakPtr(),
797 flush_timeout,
798 cb = std::move(callback)](auto result) mutable {
799 if (self.is_alive() && result.is_ok()) {
800 self->flush_timeout_.Set(flush_timeout);
801 }
802 cb(result);
803 };
804
805 if (flush_timeout < std::chrono::milliseconds(1) ||
806 (flush_timeout > hci_spec::kMaxAutomaticFlushTimeoutDuration &&
807 flush_timeout != pw::chrono::SystemClock::duration::max())) {
808 callback_wrapper(ToResult(
809 pw::bluetooth::emboss::StatusCode::INVALID_HCI_COMMAND_PARAMETERS));
810 return;
811 }
812
813 uint16_t converted_flush_timeout;
814 if (flush_timeout == pw::chrono::SystemClock::duration::max()) {
815 // The command treats a flush timeout of 0 as infinite.
816 converted_flush_timeout = 0;
817 } else {
818 // Slight imprecision from casting or converting to ms is fine for the flush
819 // timeout (a few ms difference from the requested value doesn't matter).
820 // Overflow is not possible because of the max value check above.
821 converted_flush_timeout = static_cast<uint16_t>(
822 static_cast<float>(
823 std::chrono::duration_cast<std::chrono::milliseconds>(flush_timeout)
824 .count()) *
825 hci_spec::kFlushTimeoutMsToCommandParameterConversionFactor);
826 PW_CHECK(converted_flush_timeout != 0);
827 PW_CHECK(converted_flush_timeout <=
828 hci_spec::kMaxAutomaticFlushTimeoutCommandParameterValue);
829 }
830
831 auto write_timeout = hci::CommandPacket::New<
832 pw::bluetooth::emboss::WriteAutomaticFlushTimeoutCommandWriter>(
833 hci_spec::kWriteAutomaticFlushTimeout);
834 auto write_timeout_view = write_timeout.view_t();
835 write_timeout_view.connection_handle().Write(handle_);
836 write_timeout_view.flush_timeout().Write(converted_flush_timeout);
837
838 cmd_channel_->SendCommand(
839 std::move(write_timeout),
840 [cb = std::move(callback_wrapper), handle = handle_, flush_timeout](
841 auto, const hci::EventPacket& event) mutable {
842 if (event.ToResult().is_error()) {
843 bt_log(WARN,
844 "hci",
845 "WriteAutomaticFlushTimeout command failed (result: %s, "
846 "handle: %#.4x)",
847 bt_str(event.ToResult()),
848 handle);
849 } else {
850 bt_log(DEBUG,
851 "hci",
852 "automatic flush timeout updated (handle: %#.4x, timeout: "
853 "%lld ms)",
854 handle,
855 std::chrono::duration_cast<std::chrono::milliseconds>(
856 flush_timeout)
857 .count());
858 }
859 cb(event.ToResult());
860 });
861 }
862
AttachInspect(inspect::Node & parent,std::string name)863 void LogicalLink::AttachInspect(inspect::Node& parent, std::string name) {
864 if (!parent) {
865 return;
866 }
867
868 auto node = parent.CreateChild(name);
869 inspect_properties_.handle =
870 node.CreateString(kInspectHandlePropertyName,
871 bt_lib_cpp_string::StringPrintf("%#.4x", handle_));
872 inspect_properties_.link_type =
873 node.CreateString(kInspectLinkTypePropertyName, LinkTypeToString(type_));
874 inspect_properties_.channels_node =
875 node.CreateChild(kInspectChannelsNodeName);
876 flush_timeout_.AttachInspect(node, kInspectFlushTimeoutPropertyName);
877 inspect_properties_.node = std::move(node);
878
879 for (auto& [_, chan] : channels_) {
880 chan->AttachInspect(inspect_properties_.channels_node,
881 inspect_properties_.channels_node.UniqueName(
882 kInspectChannelNodePrefix));
883 }
884 }
885
HandleNextAclPriorityRequest()886 void LogicalLink::HandleNextAclPriorityRequest() {
887 if (pending_acl_requests_.empty() || closed_) {
888 return;
889 }
890
891 auto& request = pending_acl_requests_.front();
892 PW_CHECK(request.callback);
893
894 // Prevent closed channels with queued requests from upgrading channel
895 // priority. Allow closed channels to downgrade priority so that they can
896 // clean up their priority on destruction.
897 if (!request.channel.is_alive() && request.priority != AclPriority::kNormal) {
898 request.callback(fit::failed());
899 pending_acl_requests_.pop();
900 HandleNextAclPriorityRequest();
901 return;
902 }
903
904 // Skip sending command if desired priority is already set. Do this here
905 // instead of Channel in case Channel queues up multiple requests.
906 if (request.priority == acl_priority_) {
907 request.callback(fit::ok());
908 pending_acl_requests_.pop();
909 HandleNextAclPriorityRequest();
910 return;
911 }
912
913 // If priority is not kNormal, then a channel might be using a conflicting
914 // priority, and the new priority should not be requested.
915 if (acl_priority_ != AclPriority::kNormal) {
916 for (auto& [chan_id, chan] : channels_) {
917 if ((request.channel.is_alive() &&
918 chan.get() == &request.channel.get()) ||
919 chan->requested_acl_priority() == AclPriority::kNormal) {
920 continue;
921 }
922
923 // If the request returns priority to normal but a different channel still
924 // requires high priority, skip sending command and just report success.
925 if (request.priority == AclPriority::kNormal) {
926 request.callback(fit::ok());
927 break;
928 }
929
930 // If the request tries to upgrade priority but it conflicts with another
931 // channel's priority (e.g. sink vs. source), report an error.
932 if (request.priority != chan->requested_acl_priority()) {
933 request.callback(fit::failed());
934 break;
935 }
936 }
937
938 if (!request.callback) {
939 pending_acl_requests_.pop();
940 HandleNextAclPriorityRequest();
941 return;
942 }
943 }
944
945 auto cb_wrapper = [self = GetWeakPtr(),
946 cb = std::move(request.callback),
947 priority = request.priority](auto result) mutable {
948 if (!self.is_alive()) {
949 return;
950 }
951 if (result.is_ok()) {
952 self->acl_priority_ = priority;
953 }
954 cb(result);
955 self->pending_acl_requests_.pop();
956 self->HandleNextAclPriorityRequest();
957 };
958
959 acl_data_channel_->RequestAclPriority(
960 request.priority, handle_, std::move(cb_wrapper));
961 }
962
ServeConnectionParameterUpdateRequest()963 void LogicalLink::ServeConnectionParameterUpdateRequest() {
964 PW_CHECK(signaling_channel_);
965 PW_CHECK(type_ == bt::LinkType::kLE);
966
967 LowEnergyCommandHandler cmd_handler(signaling_channel_.get());
968 cmd_handler.ServeConnectionParameterUpdateRequest(
969 fit::bind_member<&LogicalLink::OnRxConnectionParameterUpdateRequest>(
970 this));
971 }
972
OnRxConnectionParameterUpdateRequest(uint16_t interval_min,uint16_t interval_max,uint16_t peripheral_latency,uint16_t timeout_multiplier,LowEnergyCommandHandler::ConnectionParameterUpdateResponder * responder)973 void LogicalLink::OnRxConnectionParameterUpdateRequest(
974 uint16_t interval_min,
975 uint16_t interval_max,
976 uint16_t peripheral_latency,
977 uint16_t timeout_multiplier,
978 LowEnergyCommandHandler::ConnectionParameterUpdateResponder* responder) {
979 // Only a LE peripheral can send this command. "If a Peripheral’s Host
980 // receives an L2CAP_CONNECTION_PARAMETER_UPDATE_REQ packet it shall respond
981 // with an L2CAP_COMMAND_REJECT_RSP packet with reason 0x0000 (Command not
982 // understood)." (v5.0, Vol 3, Part A, Section 4.20)
983 if (role_ == pw::bluetooth::emboss::ConnectionRole::PERIPHERAL) {
984 bt_log(
985 DEBUG, "l2cap", "rejecting conn. param. update request from central");
986 responder->RejectNotUnderstood();
987 return;
988 }
989
990 // Reject the connection parameters if they are outside the ranges allowed by
991 // the HCI specification (see HCI_LE_Connection_Update command v5.0, Vol 2,
992 // Part E, Section 7.8.18).
993 bool reject = false;
994
995 hci_spec::LEPreferredConnectionParameters params(
996 interval_min, interval_max, peripheral_latency, timeout_multiplier);
997
998 if (params.min_interval() > params.max_interval()) {
999 bt_log(DEBUG, "l2cap", "conn. min interval larger than max");
1000 reject = true;
1001 } else if (params.min_interval() < hci_spec::kLEConnectionIntervalMin) {
1002 bt_log(DEBUG,
1003 "l2cap",
1004 "conn. min interval outside allowed range: %#.4x",
1005 params.min_interval());
1006 reject = true;
1007 } else if (params.max_interval() > hci_spec::kLEConnectionIntervalMax) {
1008 bt_log(DEBUG,
1009 "l2cap",
1010 "conn. max interval outside allowed range: %#.4x",
1011 params.max_interval());
1012 reject = true;
1013 } else if (params.max_latency() > hci_spec::kLEConnectionLatencyMax) {
1014 bt_log(DEBUG,
1015 "l2cap",
1016 "conn. peripheral latency too large: %#.4x",
1017 params.max_latency());
1018 reject = true;
1019 } else if (params.supervision_timeout() <
1020 hci_spec::kLEConnectionSupervisionTimeoutMin ||
1021 params.supervision_timeout() >
1022 hci_spec::kLEConnectionSupervisionTimeoutMax) {
1023 bt_log(DEBUG,
1024 "l2cap",
1025 "conn supv. timeout outside allowed range: %#.4x",
1026 params.supervision_timeout());
1027 reject = true;
1028 }
1029
1030 ConnectionParameterUpdateResult result =
1031 reject ? ConnectionParameterUpdateResult::kRejected
1032 : ConnectionParameterUpdateResult::kAccepted;
1033 responder->Send(result);
1034
1035 if (!reject) {
1036 if (!connection_parameter_update_callback_) {
1037 bt_log(DEBUG,
1038 "l2cap",
1039 "no callback set for LE Connection Parameter Update Request");
1040 return;
1041 }
1042
1043 connection_parameter_update_callback_(params);
1044 }
1045 }
1046 } // namespace bt::l2cap::internal
1047