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