• 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 "l2cap/le/internal/signalling_manager.h"
18 
19 #include <chrono>
20 
21 #include "common/bind.h"
22 #include "l2cap/internal/data_pipeline_manager.h"
23 #include "l2cap/internal/dynamic_channel_impl.h"
24 #include "l2cap/internal/le_credit_based_channel_data_controller.h"
25 #include "l2cap/l2cap_packets.h"
26 #include "l2cap/le/internal/link.h"
27 #include "os/log.h"
28 #include "packet/raw_builder.h"
29 
30 namespace bluetooth {
31 namespace l2cap {
32 namespace le {
33 namespace internal {
34 
35 static constexpr auto kTimeout = std::chrono::seconds(3);
36 
LeSignallingManager(os::Handler * handler,Link * link,l2cap::internal::DataPipelineManager * data_pipeline_manager,DynamicChannelServiceManagerImpl * dynamic_service_manager,l2cap::internal::DynamicChannelAllocator * channel_allocator)37 LeSignallingManager::LeSignallingManager(os::Handler* handler, Link* link,
38                                          l2cap::internal::DataPipelineManager* data_pipeline_manager,
39                                          DynamicChannelServiceManagerImpl* dynamic_service_manager,
40                                          l2cap::internal::DynamicChannelAllocator* channel_allocator)
41     : handler_(handler), link_(link), data_pipeline_manager_(data_pipeline_manager),
42       dynamic_service_manager_(dynamic_service_manager), channel_allocator_(channel_allocator), alarm_(handler) {
43   ASSERT(handler_ != nullptr);
44   ASSERT(link_ != nullptr);
45   signalling_channel_ = link_->AllocateFixedChannel(kLeSignallingCid, {});
46   signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
47       handler_, common::Bind(&LeSignallingManager::on_incoming_packet, common::Unretained(this)));
48   enqueue_buffer_ =
49       std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
50 }
51 
~LeSignallingManager()52 LeSignallingManager::~LeSignallingManager() {
53   enqueue_buffer_.reset();
54   signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
55   signalling_channel_ = nullptr;
56 }
57 
SendConnectionRequest(Psm psm,Cid local_cid,Mtu mtu)58 void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) {
59   PendingCommand pending_command = {
60       next_signal_id_, LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST, psm, local_cid, {}, mtu, link_->GetMps(),
61       link_->GetInitialCredit()};
62   next_signal_id_++;
63   pending_commands_.push(pending_command);
64   if (pending_commands_.size() == 1) {
65     handle_send_next_command();
66   }
67 }
68 
SendDisconnectRequest(Cid local_cid,Cid remote_cid)69 void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) {
70   PendingCommand pending_command = {
71       next_signal_id_, LeCommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}, {}};
72   next_signal_id_++;
73   pending_commands_.push(pending_command);
74   if (pending_commands_.size() == 1) {
75     handle_send_next_command();
76   }
77 }
78 
SendConnectionParameterUpdateRequest(uint16_t interval_min,uint16_t interval_max,uint16_t slave_latency,uint16_t timeout_multiplier)79 void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max,
80                                                                uint16_t slave_latency, uint16_t timeout_multiplier) {
81   LOG_ERROR("Not implemented");
82 }
83 
SendConnectionParameterUpdateResponse(SignalId signal_id,ConnectionParameterUpdateResponseResult result)84 void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id,
85                                                                 ConnectionParameterUpdateResponseResult result) {
86   auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(), result);
87   enqueue_buffer_->Enqueue(std::move(builder), handler_);
88 }
89 
SendCredit(Cid local_cid,uint16_t credits)90 void LeSignallingManager::SendCredit(Cid local_cid, uint16_t credits) {
91   auto builder = LeFlowControlCreditBuilder::Create(next_signal_id_.Value(), local_cid, credits);
92   next_signal_id_++;
93   enqueue_buffer_->Enqueue(std::move(builder), handler_);
94 }
95 
CancelAlarm()96 void LeSignallingManager::CancelAlarm() {
97   alarm_.Cancel();
98 }
99 
OnCommandReject(LeCommandRejectView command_reject_view)100 void LeSignallingManager::OnCommandReject(LeCommandRejectView command_reject_view) {
101   auto signal_id = command_reject_view.GetIdentifier();
102   if (signal_id != command_just_sent_.signal_id_ || command_just_sent_.command_code_ != command_reject_view.GetCode()) {
103     LOG_WARN("Unexpected response: no pending request");
104     return;
105   }
106   alarm_.Cancel();
107   handle_send_next_command();
108 
109   LOG_WARN("Command rejected");
110 }
111 
OnConnectionParameterUpdateRequest(uint16_t interval_min,uint16_t interval_max,uint16_t slave_latency,uint16_t timeout_multiplier)112 void LeSignallingManager::OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max,
113                                                              uint16_t slave_latency, uint16_t timeout_multiplier) {
114   LOG_ERROR("Not implemented");
115 }
116 
OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result)117 void LeSignallingManager::OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result) {
118   LOG_ERROR("Not implemented");
119 }
120 
OnConnectionRequest(SignalId signal_id,Psm psm,Cid remote_cid,Mtu mtu,uint16_t mps,uint16_t initial_credits)121 void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps,
122                                               uint16_t initial_credits) {
123   if (!IsPsmValid(psm)) {
124     LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
125     send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
126                              LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
127     return;
128   }
129 
130   if (remote_cid == kInvalidCid) {
131     LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
132     send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
133                              LeCreditBasedConnectionResponseResult::INVALID_SOURCE_CID);
134     return;
135   }
136 
137   if (channel_allocator_->IsPsmUsed(psm)) {
138     LOG_WARN("Psm already exists");
139     send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
140                              LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
141     return;
142   }
143 
144   if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
145     LOG_INFO("Service for this psm (%d) is not registered", psm);
146     send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
147                              LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
148     return;
149   }
150 
151   auto* service = dynamic_service_manager_->GetService(psm);
152   auto config = service->GetConfigOption();
153   auto local_mtu = config.mtu;
154   auto local_mps = link_->GetMps();
155 
156   auto new_channel = link_->AllocateDynamicChannel(psm, remote_cid, {});
157   if (new_channel == nullptr) {
158     LOG_WARN("Can't allocate dynamic channel");
159     send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
160                              LeCreditBasedConnectionResponseResult::NO_RESOURCES_AVAILABLE);
161 
162     return;
163   }
164   send_connection_response(signal_id, remote_cid, local_mtu, local_mps, link_->GetInitialCredit(),
165                            LeCreditBasedConnectionResponseResult::SUCCESS);
166   auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
167       data_pipeline_manager_->GetDataController(new_channel->GetCid()));
168   data_controller->SetMtu(std::min(mtu, local_mtu));
169   data_controller->SetMps(std::min(mps, local_mps));
170   data_controller->OnCredit(initial_credits);
171   auto user_channel = std::make_unique<DynamicChannel>(new_channel, handler_);
172   dynamic_service_manager_->GetService(psm)->NotifyChannelCreation(std::move(user_channel));
173 }
174 
OnConnectionResponse(SignalId signal_id,Cid remote_cid,Mtu mtu,uint16_t mps,uint16_t initial_credits,LeCreditBasedConnectionResponseResult result)175 void LeSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Mtu mtu, uint16_t mps,
176                                                uint16_t initial_credits, LeCreditBasedConnectionResponseResult result) {
177   if (signal_id != command_just_sent_.signal_id_) {
178     LOG_WARN("Unexpected response: no pending request");
179     return;
180   }
181   if (command_just_sent_.command_code_ != LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST) {
182     LOG_WARN("Unexpected response: no pending request");
183     return;
184   }
185   alarm_.Cancel();
186   command_just_sent_.signal_id_ = kInitialSignalId;
187   if (result != LeCreditBasedConnectionResponseResult::SUCCESS) {
188     LOG_WARN("Connection failed: %s", LeCreditBasedConnectionResponseResultText(result).data());
189     link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
190     handle_send_next_command();
191     return;
192   }
193   auto new_channel =
194       link_->AllocateReservedDynamicChannel(command_just_sent_.source_cid_, command_just_sent_.psm_, remote_cid, {});
195   if (new_channel == nullptr) {
196     LOG_WARN("Can't allocate dynamic channel");
197     link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
198     handle_send_next_command();
199     return;
200   }
201   auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
202       data_pipeline_manager_->GetDataController(new_channel->GetCid()));
203   data_controller->SetMtu(std::min(mtu, command_just_sent_.mtu_));
204   data_controller->SetMps(std::min(mps, command_just_sent_.mps_));
205   data_controller->OnCredit(initial_credits);
206   std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(new_channel, handler_);
207   dynamic_service_manager_->GetService(command_just_sent_.psm_)->NotifyChannelCreation(std::move(user_channel));
208 }
209 
OnDisconnectionRequest(SignalId signal_id,Cid cid,Cid remote_cid)210 void LeSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
211   auto channel = channel_allocator_->FindChannelByCid(cid);
212   if (channel == nullptr) {
213     LOG_WARN("Disconnect request for an unknown channel");
214     return;
215   }
216   if (channel->GetRemoteCid() != remote_cid) {
217     LOG_WARN("Disconnect request for an unmatching channel");
218     return;
219   }
220   auto builder = LeDisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
221   enqueue_buffer_->Enqueue(std::move(builder), handler_);
222   channel->OnClosed(hci::ErrorCode::SUCCESS);
223   link_->FreeDynamicChannel(cid);
224 }
225 
OnDisconnectionResponse(SignalId signal_id,Cid cid,Cid remote_cid)226 void LeSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid) {
227   if (signal_id != command_just_sent_.signal_id_ ||
228       command_just_sent_.command_code_ != LeCommandCode::DISCONNECTION_REQUEST) {
229     LOG_WARN("Unexpected response: no pending request");
230     return;
231   }
232   if (command_just_sent_.source_cid_ != cid || command_just_sent_.destination_cid_ != remote_cid) {
233     LOG_WARN("Unexpected response: cid doesn't match. Expected scid %d dcid %d, got scid %d dcid %d",
234              command_just_sent_.source_cid_, command_just_sent_.destination_cid_, cid, remote_cid);
235     handle_send_next_command();
236     return;
237   }
238   alarm_.Cancel();
239   command_just_sent_.signal_id_ = kInitialSignalId;
240   auto channel = channel_allocator_->FindChannelByCid(cid);
241   if (channel == nullptr) {
242     LOG_WARN("Disconnect response for an unknown channel");
243     handle_send_next_command();
244     return;
245   }
246 
247   channel->OnClosed(hci::ErrorCode::SUCCESS);
248   link_->FreeDynamicChannel(cid);
249   handle_send_next_command();
250 }
251 
OnCredit(Cid remote_cid,uint16_t credits)252 void LeSignallingManager::OnCredit(Cid remote_cid, uint16_t credits) {
253   auto channel = channel_allocator_->FindChannelByRemoteCid(remote_cid);
254   if (channel == nullptr) {
255     LOG_WARN("Received credit for invalid cid %d", channel->GetCid());
256     return;
257   }
258   auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
259       data_pipeline_manager_->GetDataController(channel->GetCid()));
260   data_controller->OnCredit(credits);
261 }
262 
on_incoming_packet()263 void LeSignallingManager::on_incoming_packet() {
264   auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
265   LeControlView control_packet_view = LeControlView::Create(*packet);
266   if (!control_packet_view.IsValid()) {
267     LOG_WARN("Invalid signalling packet received");
268     return;
269   }
270   auto code = control_packet_view.GetCode();
271   switch (code) {
272     case LeCommandCode::COMMAND_REJECT: {
273       LeCommandRejectView command_reject_view = LeCommandRejectView::Create(control_packet_view);
274       if (!command_reject_view.IsValid()) {
275         return;
276       }
277       OnCommandReject(command_reject_view);
278       return;
279     }
280 
281     case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
282       ConnectionParameterUpdateRequestView parameter_update_req_view =
283           ConnectionParameterUpdateRequestView::Create(control_packet_view);
284       if (!parameter_update_req_view.IsValid()) {
285         return;
286       }
287       OnConnectionParameterUpdateRequest(
288           parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(),
289           parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier());
290       return;
291     }
292     case LeCommandCode::CONNECTION_PARAMETER_UPDATE_RESPONSE: {
293       ConnectionParameterUpdateResponseView parameter_update_rsp_view =
294           ConnectionParameterUpdateResponseView::Create(control_packet_view);
295       if (!parameter_update_rsp_view.IsValid()) {
296         return;
297       }
298       OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetResult());
299       return;
300     }
301     case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: {
302       LeCreditBasedConnectionRequestView connection_request_view =
303           LeCreditBasedConnectionRequestView::Create(control_packet_view);
304       if (!connection_request_view.IsValid()) {
305         return;
306       }
307       OnConnectionRequest(connection_request_view.GetIdentifier(), connection_request_view.GetLePsm(),
308                           connection_request_view.GetSourceCid(), connection_request_view.GetMtu(),
309                           connection_request_view.GetMps(), connection_request_view.GetInitialCredits());
310       return;
311     }
312     case LeCommandCode::LE_CREDIT_BASED_CONNECTION_RESPONSE: {
313       LeCreditBasedConnectionResponseView connection_response_view =
314           LeCreditBasedConnectionResponseView::Create(control_packet_view);
315       if (!connection_response_view.IsValid()) {
316         return;
317       }
318       OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
319                            connection_response_view.GetMtu(), connection_response_view.GetMps(),
320                            connection_response_view.GetInitialCredits(), connection_response_view.GetResult());
321       return;
322     }
323     case LeCommandCode::LE_FLOW_CONTROL_CREDIT: {
324       LeFlowControlCreditView credit_view = LeFlowControlCreditView::Create(control_packet_view);
325       if (!credit_view.IsValid()) {
326         return;
327       }
328       OnCredit(credit_view.GetCid(), credit_view.GetCredits());
329       return;
330     }
331     case LeCommandCode::DISCONNECTION_REQUEST: {
332       LeDisconnectionRequestView disconnection_request_view = LeDisconnectionRequestView::Create(control_packet_view);
333       if (!disconnection_request_view.IsValid()) {
334         return;
335       }
336       OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
337                              disconnection_request_view.GetSourceCid());
338       return;
339     }
340     case LeCommandCode::DISCONNECTION_RESPONSE: {
341       LeDisconnectionResponseView disconnection_response_view =
342           LeDisconnectionResponseView::Create(control_packet_view);
343       if (!disconnection_response_view.IsValid()) {
344         return;
345       }
346       OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
347                               disconnection_response_view.GetDestinationCid(),
348                               disconnection_response_view.GetSourceCid());
349       return;
350     }
351     default:
352       LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
353       auto builder = LeCommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier());
354       enqueue_buffer_->Enqueue(std::move(builder), handler_);
355       return;
356   }
357 }
358 
send_connection_response(SignalId signal_id,Cid local_cid,Mtu mtu,uint16_t mps,uint16_t initial_credit,LeCreditBasedConnectionResponseResult result)359 void LeSignallingManager::send_connection_response(SignalId signal_id, Cid local_cid, Mtu mtu, uint16_t mps,
360                                                    uint16_t initial_credit,
361                                                    LeCreditBasedConnectionResponseResult result) {
362   auto builder =
363       LeCreditBasedConnectionResponseBuilder::Create(signal_id.Value(), local_cid, mtu, mps, initial_credit, result);
364   enqueue_buffer_->Enqueue(std::move(builder), handler_);
365 }
366 
on_command_timeout()367 void LeSignallingManager::on_command_timeout() {
368   LOG_WARN("Response time out");
369   if (command_just_sent_.signal_id_ == kInvalidSignalId) {
370     LOG_ERROR("No pending command");
371     return;
372   }
373   switch (command_just_sent_.command_code_) {
374     case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
375       link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
376       break;
377     }
378     default:
379       break;
380   }
381   handle_send_next_command();
382 }
383 
handle_send_next_command()384 void LeSignallingManager::handle_send_next_command() {
385   command_just_sent_.signal_id_ = kInvalidSignalId;
386   if (pending_commands_.empty()) {
387     return;
388   }
389 
390   command_just_sent_ = pending_commands_.front();
391   pending_commands_.pop();
392   switch (command_just_sent_.command_code_) {
393     case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: {
394       auto builder = LeCreditBasedConnectionRequestBuilder::Create(
395           command_just_sent_.signal_id_.Value(), command_just_sent_.psm_, command_just_sent_.source_cid_,
396           command_just_sent_.mtu_, command_just_sent_.mps_, command_just_sent_.credits_);
397       enqueue_buffer_->Enqueue(std::move(builder), handler_);
398       alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
399       break;
400     }
401     case LeCommandCode::DISCONNECTION_REQUEST: {
402       auto builder = LeDisconnectionRequestBuilder::Create(
403           command_just_sent_.signal_id_.Value(), command_just_sent_.destination_cid_, command_just_sent_.source_cid_);
404       enqueue_buffer_->Enqueue(std::move(builder), handler_);
405       alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
406       break;
407     }
408     default: {
409       LOG_WARN("Unsupported command code 0x%x", static_cast<int>(command_just_sent_.command_code_));
410     }
411   }
412 }
413 }  // namespace internal
414 }  // namespace le
415 }  // namespace l2cap
416 }  // namespace bluetooth
417