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