• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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