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