1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <memory>
17 #include <unordered_map>
18
19 #include "hci/acl_manager.h"
20 #include "hci/address.h"
21 #include "l2cap/internal/scheduler_fifo.h"
22 #include "l2cap/le/internal/link.h"
23 #include "os/handler.h"
24 #include "os/log.h"
25
26 #include "l2cap/le/internal/link_manager.h"
27
28 namespace bluetooth {
29 namespace l2cap {
30 namespace le {
31 namespace internal {
32
ConnectFixedChannelServices(hci::AddressWithType address_with_type,PendingFixedChannelConnection pending_fixed_channel_connection)33 void LinkManager::ConnectFixedChannelServices(hci::AddressWithType address_with_type,
34 PendingFixedChannelConnection pending_fixed_channel_connection) {
35 // Check if there is any service registered
36 auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
37 if (fixed_channel_services.empty()) {
38 // If so, return error
39 pending_fixed_channel_connection.handler_->Post(common::BindOnce(
40 std::move(pending_fixed_channel_connection.on_fail_callback_),
41 FixedChannelManager::ConnectionResult{
42 .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
43 return;
44 }
45 // Otherwise, check if device has an ACL connection
46 auto* link = GetLink(address_with_type);
47 if (link != nullptr) {
48 // If device already have an ACL connection
49 // Check if all registered services have an allocated channel and allocate one if not already allocated
50 int num_new_channels = 0;
51 for (auto& fixed_channel_service : fixed_channel_services) {
52 if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
53 // This channel is already allocated for this link, do not allocated twice
54 continue;
55 }
56 // Allocate channel for newly registered fixed channels
57 auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
58 fixed_channel_service.second->NotifyChannelCreation(
59 std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
60 num_new_channels++;
61 }
62 // Declare connection failure if no new channels are created
63 if (num_new_channels == 0) {
64 pending_fixed_channel_connection.handler_->Post(common::BindOnce(
65 std::move(pending_fixed_channel_connection.on_fail_callback_),
66 FixedChannelManager::ConnectionResult{
67 .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
68 }
69 // No need to create ACL connection, return without saving any pending connections
70 return;
71 }
72 // If not, create new ACL connection
73 // Add request to pending link list first
74 auto pending_link = pending_links_.find(address_with_type);
75 if (pending_link == pending_links_.end()) {
76 // Create pending link if not exist
77 pending_links_.try_emplace(address_with_type);
78 pending_link = pending_links_.find(address_with_type);
79 }
80 pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
81 // Then create new ACL connection
82 acl_manager_->CreateLeConnection(address_with_type);
83 }
84
ConnectDynamicChannelServices(hci::AddressWithType device,Link::PendingDynamicChannelConnection pending_dynamic_channel_connection,Psm psm)85 void LinkManager::ConnectDynamicChannelServices(
86 hci::AddressWithType device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) {
87 auto* link = GetLink(device);
88 if (link == nullptr) {
89 acl_manager_->CreateLeConnection(device);
90 pending_dynamic_channels_[device].push_back(std::make_pair(psm, std::move(pending_dynamic_channel_connection)));
91 return;
92 }
93 link->SendConnectionRequest(psm, std::move(pending_dynamic_channel_connection));
94 }
95
GetLink(hci::AddressWithType address_with_type)96 Link* LinkManager::GetLink(hci::AddressWithType address_with_type) {
97 if (links_.find(address_with_type) == links_.end()) {
98 return nullptr;
99 }
100 return &links_.find(address_with_type)->second;
101 }
102
OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,std::unique_ptr<hci::AclConnection> acl_connection)103 void LinkManager::OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
104 std::unique_ptr<hci::AclConnection> acl_connection) {
105 // Same link should not be connected twice
106 hci::AddressWithType connected_address_with_type(acl_connection->GetAddress(), acl_connection->GetAddressType());
107 ASSERT_LOG(GetLink(connected_address_with_type) == nullptr, "%s is connected twice without disconnection",
108 acl_connection->GetAddress().ToString().c_str());
109 // Register ACL disconnection callback in LinkManager so that we can clean up link resource properly
110 acl_connection->RegisterDisconnectCallback(
111 common::BindOnce(&LinkManager::OnDisconnect, common::Unretained(this), connected_address_with_type),
112 l2cap_handler_);
113 links_.try_emplace(connected_address_with_type, l2cap_handler_, std::move(acl_connection), parameter_provider_,
114 dynamic_channel_service_manager_, fixed_channel_service_manager_);
115 auto* link = GetLink(connected_address_with_type);
116 // Allocate and distribute channels for all registered fixed channel services
117 auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
118 for (auto& fixed_channel_service : fixed_channel_services) {
119 auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
120 fixed_channel_service.second->NotifyChannelCreation(
121 std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
122 }
123 if (pending_dynamic_channels_.find(connected_address_with_type) != pending_dynamic_channels_.end()) {
124 for (auto& psm_callback : pending_dynamic_channels_[connected_address_with_type]) {
125 link->SendConnectionRequest(psm_callback.first, std::move(psm_callback.second));
126 }
127 pending_dynamic_channels_.erase(connected_address_with_type);
128 }
129
130 // Remove device from pending links list, if any
131 auto pending_link = pending_links_.find(connecting_address_with_type);
132 if (pending_link == pending_links_.end()) {
133 // This an incoming connection, exit
134 return;
135 }
136 // This is an outgoing connection, remove entry in pending link list
137 pending_links_.erase(pending_link);
138 }
139
OnLeConnectFail(hci::AddressWithType address_with_type,hci::ErrorCode reason)140 void LinkManager::OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) {
141 // Notify all pending links for this device
142 auto pending_link = pending_links_.find(address_with_type);
143 if (pending_link == pending_links_.end()) {
144 // There is no pending link, exit
145 LOG_DEBUG("Connection to %s failed without a pending link", address_with_type.ToString().c_str());
146 return;
147 }
148 for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
149 pending_fixed_channel_connection.handler_->Post(common::BindOnce(
150 std::move(pending_fixed_channel_connection.on_fail_callback_),
151 FixedChannelManager::ConnectionResult{
152 .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
153 }
154 // Remove entry in pending link list
155 pending_links_.erase(pending_link);
156 }
157
OnDisconnect(hci::AddressWithType address_with_type,hci::ErrorCode status)158 void LinkManager::OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status) {
159 auto* link = GetLink(address_with_type);
160 ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database",
161 address_with_type.ToString().c_str(), static_cast<uint8_t>(status));
162 link->OnAclDisconnected(status);
163 links_.erase(address_with_type);
164 }
165
166 } // namespace internal
167 } // namespace le
168 } // namespace l2cap
169 } // namespace bluetooth
170