• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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