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
17 #include <chrono>
18 #include <memory>
19
20 #include "hci/acl_manager.h"
21 #include "l2cap/internal/dynamic_channel_impl.h"
22 #include "l2cap/internal/parameter_provider.h"
23 #include "l2cap/le/dynamic_channel_manager.h"
24 #include "l2cap/le/internal/fixed_channel_impl.h"
25 #include "l2cap/le/internal/link.h"
26 #include "os/alarm.h"
27
28 namespace bluetooth {
29 namespace l2cap {
30 namespace le {
31 namespace internal {
32
Link(os::Handler * l2cap_handler,std::unique_ptr<hci::AclConnection> acl_connection,l2cap::internal::ParameterProvider * parameter_provider,DynamicChannelServiceManagerImpl * dynamic_service_manager,FixedChannelServiceManagerImpl * fixed_service_manager)33 Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
34 l2cap::internal::ParameterProvider* parameter_provider,
35 DynamicChannelServiceManagerImpl* dynamic_service_manager,
36 FixedChannelServiceManagerImpl* fixed_service_manager)
37 : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)),
38 data_pipeline_manager_(l2cap_handler, this, acl_connection_->GetAclQueueEnd()),
39 parameter_provider_(parameter_provider), dynamic_service_manager_(dynamic_service_manager),
40 signalling_manager_(l2cap_handler_, this, &data_pipeline_manager_, dynamic_service_manager_,
41 &dynamic_channel_allocator_) {
42 ASSERT(l2cap_handler_ != nullptr);
43 ASSERT(acl_connection_ != nullptr);
44 ASSERT(parameter_provider_ != nullptr);
45 link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
46 parameter_provider_->GetLeLinkIdleDisconnectTimeout());
47 }
48
OnAclDisconnected(hci::ErrorCode status)49 void Link::OnAclDisconnected(hci::ErrorCode status) {
50 fixed_channel_allocator_.OnAclDisconnected(status);
51 dynamic_channel_allocator_.OnAclDisconnected(status);
52 }
53
Disconnect()54 void Link::Disconnect() {
55 acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
56 }
57
UpdateConnectionParameter(SignalId signal_id,uint16_t conn_interval_min,uint16_t conn_interval_max,uint16_t conn_latency,uint16_t supervision_timeout)58 void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
59 uint16_t conn_latency, uint16_t supervision_timeout) {
60 acl_connection_->LeConnectionUpdate(
61 conn_interval_min, conn_interval_max, conn_latency, supervision_timeout,
62 common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_);
63 }
64
AllocateFixedChannel(Cid cid,SecurityPolicy security_policy)65 std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
66 auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
67 data_pipeline_manager_.AttachChannel(cid, channel, l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
68 return channel;
69 }
70
IsFixedChannelAllocated(Cid cid)71 bool Link::IsFixedChannelAllocated(Cid cid) {
72 return fixed_channel_allocator_.IsChannelAllocated(cid);
73 }
74
ReserveDynamicChannel()75 Cid Link::ReserveDynamicChannel() {
76 return dynamic_channel_allocator_.ReserveChannel();
77 }
78
SendConnectionRequest(Psm psm,PendingDynamicChannelConnection pending_dynamic_channel_connection)79 void Link::SendConnectionRequest(Psm psm, PendingDynamicChannelConnection pending_dynamic_channel_connection) {
80 if (dynamic_channel_allocator_.IsPsmUsed(psm)) {
81 LOG_INFO("Psm %d is already connected", psm);
82 return;
83 }
84 auto reserved_cid = ReserveDynamicChannel();
85 signalling_manager_.SendConnectionRequest(psm, reserved_cid, pending_dynamic_channel_connection.configuration_.mtu);
86 }
87
SendDisconnectionRequest(Cid local_cid,Cid remote_cid)88 void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
89 auto channel = dynamic_channel_allocator_.FindChannelByCid(local_cid);
90 if (channel == nullptr || channel->GetRemoteCid() != remote_cid) {
91 LOG_ERROR("Invalid cid");
92 }
93 signalling_manager_.SendDisconnectRequest(local_cid, remote_cid);
94 }
95
OnOutgoingConnectionRequestFail(Cid local_cid)96 void Link::OnOutgoingConnectionRequestFail(Cid local_cid) {
97 local_cid_to_pending_dynamic_channel_connection_map_.erase(local_cid);
98 dynamic_channel_allocator_.FreeChannel(local_cid);
99 }
100
AllocateDynamicChannel(Psm psm,Cid remote_cid,SecurityPolicy security_policy)101 std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
102 SecurityPolicy security_policy) {
103 auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
104 if (channel != nullptr) {
105 data_pipeline_manager_.AttachChannel(channel->GetCid(), channel,
106 l2cap::internal::DataPipelineManager::ChannelMode::LE_CREDIT_BASED);
107 RefreshRefCount();
108 channel->local_initiated_ = false;
109 }
110 return channel;
111 }
112
AllocateReservedDynamicChannel(Cid reserved_cid,Psm psm,Cid remote_cid,SecurityPolicy security_policy)113 std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateReservedDynamicChannel(
114 Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy) {
115 auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
116 if (channel != nullptr) {
117 data_pipeline_manager_.AttachChannel(channel->GetCid(), channel,
118 l2cap::internal::DataPipelineManager::ChannelMode::LE_CREDIT_BASED);
119 RefreshRefCount();
120 channel->local_initiated_ = true;
121 }
122 return channel;
123 }
124
GetConfigurationForInitialConfiguration(Cid cid)125 DynamicChannelConfigurationOption Link::GetConfigurationForInitialConfiguration(Cid cid) {
126 ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
127 local_cid_to_pending_dynamic_channel_connection_map_.end());
128 return local_cid_to_pending_dynamic_channel_connection_map_[cid].configuration_;
129 }
130
FreeDynamicChannel(Cid cid)131 void Link::FreeDynamicChannel(Cid cid) {
132 if (dynamic_channel_allocator_.FindChannelByCid(cid) == nullptr) {
133 return;
134 }
135 data_pipeline_manager_.DetachChannel(cid);
136 dynamic_channel_allocator_.FreeChannel(cid);
137 RefreshRefCount();
138 }
139
RefreshRefCount()140 void Link::RefreshRefCount() {
141 int ref_count = 0;
142 ref_count += fixed_channel_allocator_.GetRefCount();
143 ref_count += dynamic_channel_allocator_.NumberOfChannels();
144 ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
145 if (ref_count > 0) {
146 link_idle_disconnect_alarm_.Cancel();
147 } else {
148 link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
149 parameter_provider_->GetLeLinkIdleDisconnectTimeout());
150 }
151 }
152
NotifyChannelCreation(Cid cid,std::unique_ptr<DynamicChannel> user_channel)153 void Link::NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> user_channel) {
154 ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
155 local_cid_to_pending_dynamic_channel_connection_map_.end());
156 auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
157 pending_dynamic_channel_connection.handler_->Post(
158 common::BindOnce(std::move(pending_dynamic_channel_connection.on_open_callback_), std::move(user_channel)));
159 local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
160 }
161
NotifyChannelFail(Cid cid)162 void Link::NotifyChannelFail(Cid cid) {
163 ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
164 local_cid_to_pending_dynamic_channel_connection_map_.end());
165 auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
166 // TODO(cmanton) Pass proper connection falure result to user
167 DynamicChannelManager::ConnectionResult result;
168 pending_dynamic_channel_connection.handler_->Post(
169 common::BindOnce(std::move(pending_dynamic_channel_connection.on_fail_callback_), result));
170 local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
171 }
172
GetMps() const173 uint16_t Link::GetMps() const {
174 return parameter_provider_->GetLeMps();
175 }
176
GetInitialCredit() const177 uint16_t Link::GetInitialCredit() const {
178 return parameter_provider_->GetLeInitialCredit();
179 }
180
SendLeCredit(Cid local_cid,uint16_t credit)181 void Link::SendLeCredit(Cid local_cid, uint16_t credit) {
182 signalling_manager_.SendCredit(local_cid, credit);
183 }
184
on_connection_update_complete(SignalId signal_id,hci::ErrorCode error_code)185 void Link::on_connection_update_complete(SignalId signal_id, hci::ErrorCode error_code) {
186 ConnectionParameterUpdateResponseResult result = (error_code == hci::ErrorCode::SUCCESS)
187 ? ConnectionParameterUpdateResponseResult::ACCEPTED
188 : ConnectionParameterUpdateResponseResult::REJECTED;
189 signalling_manager_.SendConnectionParameterUpdateResponse(SignalId(), result);
190 }
191
192 } // namespace internal
193 } // namespace le
194 } // namespace l2cap
195 } // namespace bluetooth
196