xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/logical_link.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/l2cap/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