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