xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/channel_manager.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/channel_manager.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
18 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/a2dp_offload_manager.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/logical_link.h"
22 
23 namespace bt::l2cap {
24 
25 namespace {
26 
27 constexpr const char* kInspectServicesNodeName = "services";
28 constexpr const char* kInspectServiceNodePrefix = "service_";
29 constexpr const char* kInspectLogicalLinksNodeName = "logical_links";
30 constexpr const char* kInspectLogicalLinkNodePrefix = "logical_link_";
31 constexpr const char* kInspectPsmPropertyName = "psm";
32 
33 }  // namespace
34 
35 class ChannelManagerImpl final : public ChannelManager {
36  public:
37   using LinkErrorCallback = fit::closure;
38 
39   ChannelManagerImpl(hci::AclDataChannel* acl_data_channel,
40                      hci::CommandChannel* cmd_channel,
41                      bool random_channel_ids,
42                      pw::async::Dispatcher& dispatcher);
43   ~ChannelManagerImpl() override;
44 
45   BrEdrFixedChannels AddACLConnection(
46       hci_spec::ConnectionHandle handle,
47       pw::bluetooth::emboss::ConnectionRole role,
48       LinkErrorCallback link_error_cb,
49       SecurityUpgradeCallback security_cb) override;
50 
51   [[nodiscard]] LEFixedChannels AddLEConnection(
52       hci_spec::ConnectionHandle handle,
53       pw::bluetooth::emboss::ConnectionRole role,
54       LinkErrorCallback link_error_cb,
55       LEConnectionParameterUpdateCallback conn_param_cb,
56       SecurityUpgradeCallback security_cb) override;
57 
58   void RemoveConnection(hci_spec::ConnectionHandle handle) override;
59 
60   void AssignLinkSecurityProperties(hci_spec::ConnectionHandle handle,
61                                     sm::SecurityProperties security) override;
62 
63   Channel::WeakPtr OpenFixedChannel(
64       hci_spec::ConnectionHandle connection_handle,
65       ChannelId channel_id) override;
66 
67   void OpenL2capChannel(hci_spec::ConnectionHandle handle,
68                         Psm psm,
69                         ChannelParameters params,
70                         ChannelCallback cb) override;
71 
72   bool RegisterService(Psm psm,
73                        ChannelParameters params,
74                        ChannelCallback cb) override;
75   void UnregisterService(Psm psm) override;
76 
77   void RequestConnectionParameterUpdate(
78       hci_spec::ConnectionHandle handle,
79       hci_spec::LEPreferredConnectionParameters params,
80       ConnectionParameterUpdateRequestCallback request_cb) override;
81 
82   void AttachInspect(inspect::Node& parent, std::string name) override;
83 
84   internal::LogicalLink::WeakPtr LogicalLinkForTesting(
85       hci_spec::ConnectionHandle handle) override;
86 
87  private:
88   // Returns a handler for data packets received from the Bluetooth controller
89   // bound to this object.
90   hci::ACLPacketHandler MakeInboundDataHandler();
91 
92   // Called when an ACL data packet is received from the controller. This method
93   // is responsible for routing the packet to the corresponding LogicalLink.
94   void OnACLDataReceived(hci::ACLDataPacketPtr data_packet);
95 
96   // Called by the various Register functions. Returns a pointer to the newly
97   // added link.
98   internal::LogicalLink* RegisterInternal(
99       hci_spec::ConnectionHandle handle,
100       bt::LinkType ll_type,
101       pw::bluetooth::emboss::ConnectionRole role,
102       size_t max_payload_size);
103 
104   // If a service (identified by |psm|) requested has been registered, return a
105   // ServiceInfo object containing preferred channel parameters and a callback
106   // that passes an inbound channel to the registrant. The callback may be
107   // called repeatedly to pass multiple channels for |psm|, but should not be
108   // stored because the service may be unregistered at a later time. Calls for
109   // unregistered services return null.
110   std::optional<ServiceInfo> QueryService(hci_spec::ConnectionHandle handle,
111                                           Psm psm);
112 
113   pw::async::Dispatcher& pw_dispatcher_;
114 
115   // Maximum sizes for data packet payloads from host to controller.
116   size_t max_acl_payload_size_;
117   size_t max_le_payload_size_;
118 
119   hci::AclDataChannel* acl_data_channel_;
120   hci::CommandChannel* cmd_channel_;
121 
122   std::unique_ptr<A2dpOffloadManager> a2dp_offload_manager_;
123 
124   using LinkMap = std::unordered_map<hci_spec::ConnectionHandle,
125                                      std::unique_ptr<internal::LogicalLink>>;
126   LinkMap ll_map_;
127   inspect::Node ll_node_;
128 
129   // Stores packets received on a connection handle before a link for it has
130   // been created.
131   using PendingPacketMap =
132       std::unordered_map<hci_spec::ConnectionHandle,
133                          std::queue<hci::ACLDataPacketPtr>>;
134   PendingPacketMap pending_packets_;
135 
136   // Store information required to create and forward channels for locally-
137   // hosted services.
138   struct ServiceData {
139     void AttachInspect(inspect::Node& parent);
140     ServiceInfo info;
141     Psm psm;
142     inspect::Node node;
143     inspect::StringProperty psm_property;
144   };
145   using ServiceMap = std::unordered_map<Psm, ServiceData>;
146   ServiceMap services_;
147   inspect::Node services_node_;
148   inspect::Node node_;
149 
150   // Stored info on whether random channel ids are requested.
151   bool random_channel_ids_;
152 
153   WeakSelf<ChannelManagerImpl> weak_self_;
154 
155   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ChannelManagerImpl);
156 };
157 
ChannelManagerImpl(hci::AclDataChannel * acl_data_channel,hci::CommandChannel * cmd_channel,bool random_channel_ids,pw::async::Dispatcher & dispatcher)158 ChannelManagerImpl::ChannelManagerImpl(hci::AclDataChannel* acl_data_channel,
159                                        hci::CommandChannel* cmd_channel,
160                                        bool random_channel_ids,
161                                        pw::async::Dispatcher& dispatcher)
162     : pw_dispatcher_(dispatcher),
163       acl_data_channel_(acl_data_channel),
164       cmd_channel_(cmd_channel),
165       a2dp_offload_manager_(
166           std::make_unique<A2dpOffloadManager>(cmd_channel_->AsWeakPtr())),
167       random_channel_ids_(random_channel_ids),
168       weak_self_(this) {
169   PW_CHECK(acl_data_channel_);
170   max_acl_payload_size_ = acl_data_channel_->GetBufferInfo().max_data_length();
171   max_le_payload_size_ = acl_data_channel_->GetLeBufferInfo().max_data_length();
172   acl_data_channel_->SetDataRxHandler(MakeInboundDataHandler());
173 
174   bt_log(DEBUG, "l2cap", "initialized");
175 }
176 
~ChannelManagerImpl()177 ChannelManagerImpl::~ChannelManagerImpl() {
178   bt_log(DEBUG, "l2cap", "shutting down");
179 
180   // Explicitly shut down all links to force associated L2CAP channels to
181   // release their strong references.
182   for (auto& [handle, link] : ll_map_) {
183     link->Close();
184   }
185 }
186 
MakeInboundDataHandler()187 hci::ACLPacketHandler ChannelManagerImpl::MakeInboundDataHandler() {
188   return [self = weak_self_.GetWeakPtr()](auto packet) {
189     if (self.is_alive()) {
190       self->OnACLDataReceived(std::move(packet));
191     }
192   };
193 }
194 
AddACLConnection(hci_spec::ConnectionHandle handle,pw::bluetooth::emboss::ConnectionRole role,LinkErrorCallback link_error_cb,SecurityUpgradeCallback security_cb)195 ChannelManagerImpl::BrEdrFixedChannels ChannelManagerImpl::AddACLConnection(
196     hci_spec::ConnectionHandle handle,
197     pw::bluetooth::emboss::ConnectionRole role,
198     LinkErrorCallback link_error_cb,
199     SecurityUpgradeCallback security_cb) {
200   bt_log(DEBUG, "l2cap", "register ACL link (handle: %#.4x)", handle);
201 
202   auto* ll =
203       RegisterInternal(handle, bt::LinkType::kACL, role, max_acl_payload_size_);
204   ll->set_error_callback(std::move(link_error_cb));
205   ll->set_security_upgrade_callback(std::move(security_cb));
206 
207   Channel::WeakPtr smp = OpenFixedChannel(handle, kSMPChannelId);
208   PW_CHECK(smp.is_alive());
209   return BrEdrFixedChannels{.smp = std::move(smp)};
210 }
211 
AddLEConnection(hci_spec::ConnectionHandle handle,pw::bluetooth::emboss::ConnectionRole role,LinkErrorCallback link_error_cb,LEConnectionParameterUpdateCallback conn_param_cb,SecurityUpgradeCallback security_cb)212 ChannelManagerImpl::LEFixedChannels ChannelManagerImpl::AddLEConnection(
213     hci_spec::ConnectionHandle handle,
214     pw::bluetooth::emboss::ConnectionRole role,
215     LinkErrorCallback link_error_cb,
216     LEConnectionParameterUpdateCallback conn_param_cb,
217     SecurityUpgradeCallback security_cb) {
218   bt_log(DEBUG, "l2cap", "register LE link (handle: %#.4x)", handle);
219 
220   auto* ll =
221       RegisterInternal(handle, bt::LinkType::kLE, role, max_le_payload_size_);
222   ll->set_error_callback(std::move(link_error_cb));
223   ll->set_security_upgrade_callback(std::move(security_cb));
224   ll->set_connection_parameter_update_callback(std::move(conn_param_cb));
225 
226   Channel::WeakPtr att = OpenFixedChannel(handle, kATTChannelId);
227   Channel::WeakPtr smp = OpenFixedChannel(handle, kLESMPChannelId);
228   PW_CHECK(att.is_alive());
229   PW_CHECK(smp.is_alive());
230   return LEFixedChannels{.att = std::move(att), .smp = std::move(smp)};
231 }
232 
RemoveConnection(hci_spec::ConnectionHandle handle)233 void ChannelManagerImpl::RemoveConnection(hci_spec::ConnectionHandle handle) {
234   bt_log(DEBUG, "l2cap", "unregister link (handle: %#.4x)", handle);
235 
236   pending_packets_.erase(handle);
237   auto iter = ll_map_.find(handle);
238   if (iter == ll_map_.end()) {
239     bt_log(DEBUG,
240            "l2cap",
241            "attempt to unregister unknown link (handle: %#.4x)",
242            handle);
243     return;
244   }
245 
246   // Explicitly shut down the link to force associated L2CAP channels to release
247   // their strong references.
248   iter->second->Close();
249   ll_map_.erase(iter);
250 }
251 
AssignLinkSecurityProperties(hci_spec::ConnectionHandle handle,sm::SecurityProperties security)252 void ChannelManagerImpl::AssignLinkSecurityProperties(
253     hci_spec::ConnectionHandle handle, sm::SecurityProperties security) {
254   bt_log(DEBUG,
255          "l2cap",
256          "received new security properties (handle: %#.4x)",
257          handle);
258 
259   auto iter = ll_map_.find(handle);
260   if (iter == ll_map_.end()) {
261     bt_log(DEBUG, "l2cap", "ignoring new security properties on unknown link");
262     return;
263   }
264 
265   iter->second->AssignSecurityProperties(security);
266 }
267 
OpenFixedChannel(hci_spec::ConnectionHandle handle,ChannelId channel_id)268 Channel::WeakPtr ChannelManagerImpl::OpenFixedChannel(
269     hci_spec::ConnectionHandle handle, ChannelId channel_id) {
270   auto iter = ll_map_.find(handle);
271   if (iter == ll_map_.end()) {
272     bt_log(ERROR,
273            "l2cap",
274            "cannot open fixed channel on unknown connection handle: %#.4x",
275            handle);
276     return Channel::WeakPtr();
277   }
278 
279   return iter->second->OpenFixedChannel(channel_id);
280 }
281 
OpenL2capChannel(hci_spec::ConnectionHandle handle,Psm psm,ChannelParameters params,ChannelCallback cb)282 void ChannelManagerImpl::OpenL2capChannel(hci_spec::ConnectionHandle handle,
283                                           Psm psm,
284                                           ChannelParameters params,
285                                           ChannelCallback cb) {
286   auto iter = ll_map_.find(handle);
287   if (iter == ll_map_.end()) {
288     bt_log(ERROR,
289            "l2cap",
290            "Cannot open channel on unknown connection handle: %#.4x",
291            handle);
292     cb(Channel::WeakPtr());
293     return;
294   }
295 
296   iter->second->OpenChannel(psm, params, std::move(cb));
297 }
298 
RegisterService(Psm psm,ChannelParameters params,ChannelCallback cb)299 bool ChannelManagerImpl::RegisterService(Psm psm,
300                                          ChannelParameters params,
301                                          ChannelCallback cb) {
302   // v5.0 Vol 3, Part A, Sec 4.2: PSMs shall be odd and the least significant
303   // bit of the most significant byte shall be zero
304   if (((psm & 0x0001) != 0x0001) || ((psm & 0x0100) != 0x0000)) {
305     return false;
306   }
307 
308   auto iter = services_.find(psm);
309   if (iter != services_.end()) {
310     return false;
311   }
312 
313   ServiceData service{.info = ServiceInfo(params, std::move(cb)),
314                       .psm = psm,
315                       .node = {},
316                       .psm_property = {}};
317   service.AttachInspect(services_node_);
318   services_.emplace(psm, std::move(service));
319   return true;
320 }
321 
UnregisterService(Psm psm)322 void ChannelManagerImpl::UnregisterService(Psm psm) { services_.erase(psm); }
323 
RequestConnectionParameterUpdate(hci_spec::ConnectionHandle handle,hci_spec::LEPreferredConnectionParameters params,ConnectionParameterUpdateRequestCallback request_cb)324 void ChannelManagerImpl::RequestConnectionParameterUpdate(
325     hci_spec::ConnectionHandle handle,
326     hci_spec::LEPreferredConnectionParameters params,
327     ConnectionParameterUpdateRequestCallback request_cb) {
328   auto iter = ll_map_.find(handle);
329   if (iter == ll_map_.end()) {
330     bt_log(DEBUG,
331            "l2cap",
332            "ignoring Connection Parameter Update request on unknown link");
333     return;
334   }
335 
336   iter->second->SendConnectionParameterUpdateRequest(params,
337                                                      std::move(request_cb));
338 }
339 
AttachInspect(inspect::Node & parent,std::string name)340 void ChannelManagerImpl::AttachInspect(inspect::Node& parent,
341                                        std::string name) {
342   if (!parent) {
343     return;
344   }
345 
346   node_ = parent.CreateChild(name);
347 
348   services_node_ = node_.CreateChild(kInspectServicesNodeName);
349   for (auto& [psm, service] : services_) {
350     service.AttachInspect(services_node_);
351   }
352 
353   ll_node_ = node_.CreateChild(kInspectLogicalLinksNodeName);
354   for (auto& [_, ll] : ll_map_) {
355     ll->AttachInspect(ll_node_,
356                       ll_node_.UniqueName(kInspectLogicalLinkNodePrefix));
357   }
358 }
359 
LogicalLinkForTesting(hci_spec::ConnectionHandle handle)360 internal::LogicalLink::WeakPtr ChannelManagerImpl::LogicalLinkForTesting(
361     hci_spec::ConnectionHandle handle) {
362   auto iter = ll_map_.find(handle);
363   if (iter == ll_map_.end()) {
364     return internal::LogicalLink::WeakPtr();
365   }
366   return iter->second->GetWeakPtr();
367 }
368 
369 // Called when an ACL data packet is received from the controller. This method
370 // is responsible for routing the packet to the corresponding LogicalLink.
OnACLDataReceived(hci::ACLDataPacketPtr packet)371 void ChannelManagerImpl::OnACLDataReceived(hci::ACLDataPacketPtr packet) {
372   auto handle = packet->connection_handle();
373   TRACE_DURATION(
374       "bluetooth", "ChannelManagerImpl::OnDataReceived", "handle", handle);
375 
376   auto iter = ll_map_.find(handle);
377   PendingPacketMap::iterator pp_iter;
378 
379   // If a LogicalLink does not exist, we set up a queue for its packets to be
380   // delivered when the LogicalLink gets created.
381   if (iter == ll_map_.end()) {
382     pp_iter =
383         pending_packets_.emplace(handle, std::queue<hci::ACLDataPacketPtr>())
384             .first;
385   } else {
386     // A logical link exists. |pp_iter| will be valid only if the drain task has
387     // not run yet (see ChannelManagerImpl::RegisterInternal()).
388     pp_iter = pending_packets_.find(handle);
389   }
390 
391   if (pp_iter != pending_packets_.end()) {
392     packet->set_trace_id(TRACE_NONCE());
393     TRACE_FLOW_BEGIN("bluetooth",
394                      "ChannelMaager::OnDataReceived queued",
395                      packet->trace_id());
396     pp_iter->second.push(std::move(packet));
397     bt_log(TRACE, "l2cap", "queued rx packet on handle: %#.4x", handle);
398     return;
399   }
400 
401   iter->second->HandleRxPacket(std::move(packet));
402 }
403 
RegisterInternal(hci_spec::ConnectionHandle handle,bt::LinkType ll_type,pw::bluetooth::emboss::ConnectionRole role,size_t max_payload_size)404 internal::LogicalLink* ChannelManagerImpl::RegisterInternal(
405     hci_spec::ConnectionHandle handle,
406     bt::LinkType ll_type,
407     pw::bluetooth::emboss::ConnectionRole role,
408     size_t max_payload_size) {
409   TRACE_DURATION(
410       "bluetooth", "ChannelManagerImpl::RegisterInternal", "handle", handle);
411 
412   // TODO(armansito): Return nullptr instead of asserting. Callers shouldn't
413   // assume this will succeed.
414   auto iter = ll_map_.find(handle);
415   PW_DCHECK(iter == ll_map_.end(),
416             "connection handle re-used! (handle=%#.4x)",
417             handle);
418 
419   auto ll = std::make_unique<internal::LogicalLink>(
420       handle,
421       ll_type,
422       role,
423       max_payload_size,
424       fit::bind_member<&ChannelManagerImpl::QueryService>(this),
425       acl_data_channel_,
426       cmd_channel_,
427       random_channel_ids_,
428       *a2dp_offload_manager_,
429       pw_dispatcher_);
430 
431   if (ll_node_) {
432     ll->AttachInspect(ll_node_,
433                       ll_node_.UniqueName(kInspectLogicalLinkNodePrefix));
434   }
435 
436   // Route all pending packets to the link.
437   auto pp_iter = pending_packets_.find(handle);
438   if (pp_iter != pending_packets_.end()) {
439     auto& packets = pp_iter->second;
440     while (!packets.empty()) {
441       auto packet = std::move(packets.front());
442       packets.pop();
443       TRACE_FLOW_END("bluetooth",
444                      "ChannelManagerImpl::OnDataReceived queued",
445                      packet->trace_id());
446       ll->HandleRxPacket(std::move(packet));
447     }
448     pending_packets_.erase(pp_iter);
449   }
450 
451   auto* ll_raw = ll.get();
452   ll_map_[handle] = std::move(ll);
453 
454   return ll_raw;
455 }
456 
QueryService(hci_spec::ConnectionHandle,Psm psm)457 std::optional<ChannelManager::ServiceInfo> ChannelManagerImpl::QueryService(
458     hci_spec::ConnectionHandle, Psm psm) {
459   auto iter = services_.find(psm);
460   if (iter == services_.end()) {
461     return std::nullopt;
462   }
463 
464   // |channel_cb| will be called in LogicalLink. Each callback in |services_|
465   // already trampolines to the appropriate dispatcher (passed to
466   // RegisterService).
467   return ServiceInfo(iter->second.info.channel_params,
468                      iter->second.info.channel_cb.share());
469 }
470 
AttachInspect(inspect::Node & parent)471 void ChannelManagerImpl::ServiceData::AttachInspect(inspect::Node& parent) {
472   if (!parent) {
473     return;
474   }
475   node = parent.CreateChild(parent.UniqueName(kInspectServiceNodePrefix));
476   psm_property = node.CreateString(kInspectPsmPropertyName, PsmToString(psm));
477 }
478 
Create(hci::AclDataChannel * acl_data_channel,hci::CommandChannel * cmd_channel,bool random_channel_ids,pw::async::Dispatcher & dispatcher)479 std::unique_ptr<ChannelManager> ChannelManager::Create(
480     hci::AclDataChannel* acl_data_channel,
481     hci::CommandChannel* cmd_channel,
482     bool random_channel_ids,
483     pw::async::Dispatcher& dispatcher) {
484   return std::make_unique<ChannelManagerImpl>(
485       acl_data_channel, cmd_channel, random_channel_ids, dispatcher);
486 }
487 
488 }  // namespace bt::l2cap
489