Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 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" |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 21 | #include "l2cap/internal/scheduler_fifo.h" |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 22 | #include "l2cap/le/internal/link.h" |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 23 | #include "os/handler.h" |
| 24 | #include "os/log.h" |
| 25 | |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 26 | #include "l2cap/le/internal/link_manager.h" |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 27 | |
| 28 | namespace bluetooth { |
| 29 | namespace l2cap { |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 30 | namespace le { |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 31 | namespace internal { |
| 32 | |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 33 | void LinkManager::ConnectFixedChannelServices(hci::AddressWithType address_with_type, |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 34 | PendingFixedChannelConnection pending_fixed_channel_connection) { |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 35 | // Check if there is any service registered |
| 36 | auto fixed_channel_services = 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_), |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 41 | FixedChannelManager::ConnectionResult{ |
| 42 | .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED})); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 43 | return; |
| 44 | } |
| 45 | // Otherwise, check if device has an ACL connection |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 46 | auto* link = GetLink(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 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( |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 59 | std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_)); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 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_), |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 66 | FixedChannelManager::ConnectionResult{ |
| 67 | .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL})); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 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 |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 74 | auto pending_link = pending_links_.find(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 75 | if (pending_link == pending_links_.end()) { |
| 76 | // Create pending link if not exist |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 77 | pending_links_.try_emplace(address_with_type); |
| 78 | pending_link = pending_links_.find(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 79 | } |
| 80 | pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection)); |
| 81 | // Then create new ACL connection |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 82 | acl_manager_->CreateLeConnection(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 83 | } |
| 84 | |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 85 | Link* LinkManager::GetLink(hci::AddressWithType address_with_type) { |
| 86 | if (links_.find(address_with_type) == links_.end()) { |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 87 | return nullptr; |
| 88 | } |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 89 | return &links_.find(address_with_type)->second; |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 90 | } |
| 91 | |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 92 | void LinkManager::OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type, |
| 93 | std::unique_ptr<hci::AclConnection> acl_connection) { |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 94 | // Same link should not be connected twice |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 95 | hci::AddressWithType connected_address_with_type(acl_connection->GetAddress(), acl_connection->GetAddressType()); |
| 96 | ASSERT_LOG(GetLink(connected_address_with_type) == nullptr, "%s is connected twice without disconnection", |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 97 | acl_connection->GetAddress().ToString().c_str()); |
| 98 | auto* link_queue_up_end = acl_connection->GetAclQueueEnd(); |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 99 | links_.try_emplace(connected_address_with_type, l2cap_handler_, std::move(acl_connection), |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 100 | std::make_unique<l2cap::internal::Fifo>(link_queue_up_end, l2cap_handler_), parameter_provider_); |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 101 | auto* link = GetLink(connected_address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 102 | // Allocate and distribute channels for all registered fixed channel services |
| 103 | auto fixed_channel_services = service_manager_->GetRegisteredServices(); |
| 104 | for (auto& fixed_channel_service : fixed_channel_services) { |
| 105 | auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy()); |
| 106 | fixed_channel_service.second->NotifyChannelCreation( |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 107 | std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_)); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 108 | } |
| 109 | // Remove device from pending links list, if any |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 110 | auto pending_link = pending_links_.find(connecting_address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 111 | if (pending_link == pending_links_.end()) { |
| 112 | // This an incoming connection, exit |
| 113 | return; |
| 114 | } |
| 115 | // This is an outgoing connection, remove entry in pending link list |
| 116 | pending_links_.erase(pending_link); |
| 117 | } |
| 118 | |
Jack He | 1d4c6df | 2019-10-21 17:03:18 -0700 | [diff] [blame^] | 119 | void LinkManager::OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) { |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 120 | // Notify all pending links for this device |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 121 | auto pending_link = pending_links_.find(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 122 | if (pending_link == pending_links_.end()) { |
| 123 | // There is no pending link, exit |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 124 | LOG_DEBUG("Connection to %s failed without a pending link", address_with_type.ToString().c_str()); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 125 | return; |
| 126 | } |
| 127 | for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) { |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 128 | pending_fixed_channel_connection.handler_->Post(common::BindOnce( |
| 129 | std::move(pending_fixed_channel_connection.on_fail_callback_), |
| 130 | FixedChannelManager::ConnectionResult{ |
| 131 | .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason})); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 132 | } |
| 133 | // Remove entry in pending link list |
| 134 | pending_links_.erase(pending_link); |
| 135 | } |
| 136 | |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 137 | void LinkManager::OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status) { |
| 138 | auto* link = GetLink(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 139 | ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database", |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 140 | address_with_type.ToString().c_str(), static_cast<uint8_t>(status)); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 141 | link->OnAclDisconnected(status); |
Jack He | 423b6be | 2019-10-21 15:03:11 -0700 | [diff] [blame] | 142 | links_.erase(address_with_type); |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | } // namespace internal |
Jack He | ff38d89 | 2019-10-03 17:11:07 -0700 | [diff] [blame] | 146 | } // namespace le |
Jack He | 492dcf7 | 2019-09-26 18:27:41 -0700 | [diff] [blame] | 147 | } // namespace l2cap |
| 148 | } // namespace bluetooth |