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_ =
46 link_->AllocateFixedChannel(kLeSignallingCid, SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK);
47 signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
48 handler_, common::Bind(&LeSignallingManager::on_incoming_packet, common::Unretained(this)));
49 enqueue_buffer_ =
50 std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
51 }
52
~LeSignallingManager()53 LeSignallingManager::~LeSignallingManager() {
54 enqueue_buffer_.reset();
55 signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
56 signalling_channel_ = nullptr;
57 }
58
SendConnectionRequest(Psm psm,Cid local_cid,Mtu mtu)59 void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) {
60 dynamic_service_manager_->GetSecurityEnforcementInterface()->Enforce(
61 link_->GetDevice(),
62 dynamic_service_manager_->GetService(psm)->GetSecurityPolicy(),
63 handler_->BindOnceOn(this, &LeSignallingManager::on_security_result_for_outgoing, psm, local_cid, mtu));
64 }
65
on_security_result_for_outgoing(Psm psm,Cid local_cid,Mtu mtu,bool result)66 void LeSignallingManager::on_security_result_for_outgoing(Psm psm, Cid local_cid, Mtu mtu, bool result) {
67 if (!result) {
68 LOG_WARN("Security requirement can't be satisfied. Dropping connection request");
69 return;
70 }
71
72 PendingCommand pending_command = PendingCommand::CreditBasedConnectionRequest(
73 next_signal_id_, psm, local_cid, mtu, link_->GetMps(), link_->GetInitialCredit());
74 next_signal_id_++;
75 pending_commands_.push(pending_command);
76 if (pending_commands_.size() == 1) {
77 handle_send_next_command();
78 }
79 }
80
SendDisconnectRequest(Cid scid,Cid dcid)81 void LeSignallingManager::SendDisconnectRequest(Cid scid, Cid dcid) {
82 PendingCommand pending_command = PendingCommand::DisconnectionRequest(next_signal_id_, scid, dcid);
83 next_signal_id_++;
84 pending_commands_.push(pending_command);
85 if (pending_commands_.size() == 1) {
86 handle_send_next_command();
87 }
88 }
89
SendConnectionParameterUpdateRequest(uint16_t interval_min,uint16_t interval_max,uint16_t slave_latency,uint16_t timeout_multiplier)90 void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max,
91 uint16_t slave_latency, uint16_t timeout_multiplier) {
92 PendingCommand pending_command = PendingCommand::ConnectionParameterUpdate(
93 next_signal_id_, interval_min, interval_max, slave_latency, timeout_multiplier);
94 next_signal_id_++;
95 pending_commands_.push(pending_command);
96 if (pending_commands_.size() == 1) {
97 handle_send_next_command();
98 }
99 }
100
SendConnectionParameterUpdateResponse(SignalId signal_id,ConnectionParameterUpdateResponseResult result)101 void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id,
102 ConnectionParameterUpdateResponseResult result) {
103 auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(), result);
104 enqueue_buffer_->Enqueue(std::move(builder), handler_);
105 }
106
SendCredit(Cid local_cid,uint16_t credits)107 void LeSignallingManager::SendCredit(Cid local_cid, uint16_t credits) {
108 auto builder = LeFlowControlCreditBuilder::Create(next_signal_id_.Value(), local_cid, credits);
109 next_signal_id_++;
110 enqueue_buffer_->Enqueue(std::move(builder), handler_);
111 }
112
CancelAlarm()113 void LeSignallingManager::CancelAlarm() {
114 alarm_.Cancel();
115 }
116
OnCommandReject(LeCommandRejectView command_reject_view)117 void LeSignallingManager::OnCommandReject(LeCommandRejectView command_reject_view) {
118 auto signal_id = command_reject_view.GetIdentifier();
119 if (signal_id != command_just_sent_.signal_id_) {
120 LOG_WARN("Unexpected response: no pending request");
121 return;
122 }
123 alarm_.Cancel();
124 if (command_just_sent_.command_code_ == LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST) {
125 link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_,
126 LeCreditBasedConnectionResponseResult::NO_RESOURCES_AVAILABLE);
127 }
128 handle_send_next_command();
129
130 LOG_WARN("Command rejected");
131 }
132
OnConnectionParameterUpdateRequest(SignalId signal_id,uint16_t interval_min,uint16_t interval_max,uint16_t slave_latency,uint16_t timeout_multiplier)133 void LeSignallingManager::OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min,
134 uint16_t interval_max, uint16_t slave_latency,
135 uint16_t timeout_multiplier) {
136 if (link_->GetRole() == hci::Role::SLAVE) {
137 LOG_WARN("Received request from LL master");
138 auto builder = LeCommandRejectNotUnderstoodBuilder::Create(signal_id.Value());
139 enqueue_buffer_->Enqueue(std::move(builder), handler_);
140 return;
141 }
142
143 if (!link_->CheckConnectionParameters(interval_min, interval_max, slave_latency, timeout_multiplier)) {
144 LOG_WARN("Received invalid connection parameter update request from LL master");
145 auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(),
146 ConnectionParameterUpdateResponseResult::REJECTED);
147 enqueue_buffer_->Enqueue(std::move(builder), handler_);
148 return;
149 }
150 link_->UpdateConnectionParameterFromRemote(signal_id, interval_min, interval_max, slave_latency, timeout_multiplier);
151 }
152
OnConnectionParameterUpdateResponse(SignalId signal_id,ConnectionParameterUpdateResponseResult result)153 void LeSignallingManager::OnConnectionParameterUpdateResponse(SignalId signal_id,
154 ConnectionParameterUpdateResponseResult result) {
155 if (signal_id != command_just_sent_.signal_id_) {
156 LOG_WARN("Unexpected response: no pending request");
157 return;
158 }
159 if (command_just_sent_.command_code_ != LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST) {
160 LOG_WARN("Unexpected response: no pending request");
161 return;
162 }
163 alarm_.Cancel();
164 command_just_sent_.signal_id_ = kInitialSignalId;
165 if (result != ConnectionParameterUpdateResponseResult::ACCEPTED) {
166 LOG_ERROR("Connection parameter update is not accepted");
167 }
168 }
169
OnConnectionRequest(SignalId signal_id,Psm psm,Cid remote_cid,Mtu mtu,uint16_t mps,uint16_t initial_credits)170 void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps,
171 uint16_t initial_credits) {
172 if (!IsPsmValid(psm)) {
173 LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
174 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
175 LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
176 return;
177 }
178
179 if (remote_cid == kInvalidCid) {
180 LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
181 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
182 LeCreditBasedConnectionResponseResult::INVALID_SOURCE_CID);
183 return;
184 }
185
186 if (channel_allocator_->IsPsmUsed(psm)) {
187 LOG_WARN("Psm already exists");
188 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
189 LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
190 return;
191 }
192
193 if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
194 LOG_INFO("Service for this psm (%d) is not registered", psm);
195 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
196 LeCreditBasedConnectionResponseResult::LE_PSM_NOT_SUPPORTED);
197 return;
198 }
199
200 PendingConnection pending{
201 .remote_cid = remote_cid,
202 .incoming_signal_id = signal_id,
203 .initial_credits = initial_credits,
204 .max_pdu_size = mps,
205 .mtu = mtu,
206 };
207 dynamic_service_manager_->GetSecurityEnforcementInterface()->Enforce(
208 link_->GetDevice(),
209 dynamic_service_manager_->GetService(psm)->GetSecurityPolicy(),
210 handler_->BindOnceOn(this, &LeSignallingManager::on_security_result_for_incoming, psm, pending));
211 }
212
on_security_result_for_incoming(Psm psm,PendingConnection request,bool result)213 void LeSignallingManager::on_security_result_for_incoming(Psm psm, PendingConnection request, bool result) {
214 auto signal_id = request.incoming_signal_id;
215 auto* service = dynamic_service_manager_->GetService(psm);
216 if (!result) {
217 auto security_policy = service->GetSecurityPolicy();
218 switch (security_policy) {
219 case SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK:
220 LOG_ERROR("If no security requirement, we should never fail");
221 break;
222 case SecurityPolicy::ENCRYPTED_TRANSPORT:
223 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
224 LeCreditBasedConnectionResponseResult::INSUFFICIENT_AUTHENTICATION);
225 return;
226 case SecurityPolicy::AUTHENTICATED_ENCRYPTED_TRANSPORT:
227 case SecurityPolicy::BEST:
228 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
229 LeCreditBasedConnectionResponseResult::INSUFFICIENT_AUTHENTICATION);
230 return;
231 case SecurityPolicy::_NOT_FOR_YOU__AUTHENTICATED_PAIRING_WITH_128_BIT_KEY:
232 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
233 LeCreditBasedConnectionResponseResult::INSUFFICIENT_ENCRYPTION_KEY_SIZE);
234 return;
235 case SecurityPolicy::_NOT_FOR_YOU__AUTHORIZATION:
236 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
237 LeCreditBasedConnectionResponseResult::INSUFFICIENT_AUTHORIZATION);
238 return;
239 }
240 }
241 auto config = service->GetConfigOption();
242 auto local_mtu = config.mtu;
243 auto local_mps = link_->GetMps();
244
245 auto new_channel = link_->AllocateDynamicChannel(psm, request.remote_cid);
246 if (new_channel == nullptr) {
247 LOG_WARN("Can't allocate dynamic channel");
248 // TODO: We need to respond with the correct reason
249 send_connection_response(signal_id, kInvalidCid, 0, 0, 0,
250 LeCreditBasedConnectionResponseResult::SOURCE_CID_ALREADY_ALLOCATED);
251 return;
252 }
253
254 send_connection_response(signal_id, new_channel->GetCid(), local_mtu, local_mps, link_->GetInitialCredit(),
255 LeCreditBasedConnectionResponseResult::SUCCESS);
256 auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
257 data_pipeline_manager_->GetDataController(new_channel->GetCid()));
258 data_controller->SetMtu(std::min(request.mtu, local_mtu));
259 data_controller->SetMps(std::min(request.max_pdu_size, local_mps));
260 data_controller->OnCredit(request.initial_credits);
261 auto user_channel = std::make_unique<DynamicChannel>(new_channel, handler_, link_);
262 dynamic_service_manager_->GetService(psm)->NotifyChannelCreation(std::move(user_channel));
263 }
264
OnConnectionResponse(SignalId signal_id,Cid remote_cid,Mtu mtu,uint16_t mps,uint16_t initial_credits,LeCreditBasedConnectionResponseResult result)265 void LeSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Mtu mtu, uint16_t mps,
266 uint16_t initial_credits, LeCreditBasedConnectionResponseResult result) {
267 if (signal_id != command_just_sent_.signal_id_) {
268 LOG_WARN("Unexpected response: no pending request");
269 return;
270 }
271 if (command_just_sent_.command_code_ != LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST) {
272 LOG_WARN("Unexpected response: no pending request");
273 return;
274 }
275 alarm_.Cancel();
276 command_just_sent_.signal_id_ = kInitialSignalId;
277 if (result != LeCreditBasedConnectionResponseResult::SUCCESS) {
278 LOG_WARN("Connection failed: %s", LeCreditBasedConnectionResponseResultText(result).data());
279 link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_, result);
280 handle_send_next_command();
281 return;
282 }
283 auto new_channel =
284 link_->AllocateReservedDynamicChannel(command_just_sent_.source_cid_, command_just_sent_.psm_, remote_cid);
285 if (new_channel == nullptr) {
286 LOG_WARN("Can't allocate dynamic channel");
287 link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_,
288 LeCreditBasedConnectionResponseResult::NO_RESOURCES_AVAILABLE);
289 handle_send_next_command();
290 return;
291 }
292 auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
293 data_pipeline_manager_->GetDataController(new_channel->GetCid()));
294 data_controller->SetMtu(std::min(mtu, command_just_sent_.mtu_));
295 data_controller->SetMps(std::min(mps, command_just_sent_.mps_));
296 data_controller->OnCredit(initial_credits);
297 std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(new_channel, handler_, link_);
298 dynamic_service_manager_->GetService(command_just_sent_.psm_)->NotifyChannelCreation(std::move(user_channel));
299 }
300
OnDisconnectionRequest(SignalId signal_id,Cid cid,Cid remote_cid)301 void LeSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
302 auto channel = channel_allocator_->FindChannelByCid(cid);
303 if (channel == nullptr) {
304 LOG_WARN("Disconnect request for an unknown channel");
305 return;
306 }
307 if (channel->GetRemoteCid() != remote_cid) {
308 LOG_WARN("Disconnect request for an unmatching channel");
309 return;
310 }
311 auto builder = LeDisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
312 enqueue_buffer_->Enqueue(std::move(builder), handler_);
313 channel->OnClosed(hci::ErrorCode::SUCCESS);
314 link_->FreeDynamicChannel(cid);
315 }
316
OnDisconnectionResponse(SignalId signal_id,Cid remote_cid,Cid cid)317 void LeSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) {
318 if (signal_id != command_just_sent_.signal_id_ ||
319 command_just_sent_.command_code_ != LeCommandCode::DISCONNECTION_REQUEST) {
320 LOG_WARN("Unexpected response: no pending request");
321 return;
322 }
323 if (command_just_sent_.source_cid_ != cid || command_just_sent_.destination_cid_ != remote_cid) {
324 LOG_WARN("Unexpected response: cid doesn't match. Expected scid %d dcid %d, got scid %d dcid %d",
325 command_just_sent_.source_cid_, command_just_sent_.destination_cid_, cid, remote_cid);
326 handle_send_next_command();
327 return;
328 }
329 alarm_.Cancel();
330 command_just_sent_.signal_id_ = kInitialSignalId;
331 auto channel = channel_allocator_->FindChannelByCid(cid);
332 if (channel == nullptr) {
333 LOG_WARN("Disconnect response for an unknown channel");
334 handle_send_next_command();
335 return;
336 }
337
338 channel->OnClosed(hci::ErrorCode::SUCCESS);
339 link_->FreeDynamicChannel(cid);
340 handle_send_next_command();
341 }
342
OnCredit(Cid remote_cid,uint16_t credits)343 void LeSignallingManager::OnCredit(Cid remote_cid, uint16_t credits) {
344 auto channel = channel_allocator_->FindChannelByRemoteCid(remote_cid);
345 if (channel == nullptr) {
346 LOG_WARN("Received credit for invalid cid %d", channel->GetCid());
347 return;
348 }
349 auto* data_controller = reinterpret_cast<l2cap::internal::LeCreditBasedDataController*>(
350 data_pipeline_manager_->GetDataController(channel->GetCid()));
351 data_controller->OnCredit(credits);
352 }
353
on_incoming_packet()354 void LeSignallingManager::on_incoming_packet() {
355 auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
356 LeControlView control_packet_view = LeControlView::Create(*packet);
357 if (!control_packet_view.IsValid()) {
358 LOG_WARN("Invalid signalling packet received");
359 return;
360 }
361 auto code = control_packet_view.GetCode();
362 switch (code) {
363 case LeCommandCode::COMMAND_REJECT: {
364 LeCommandRejectView command_reject_view = LeCommandRejectView::Create(control_packet_view);
365 if (!command_reject_view.IsValid()) {
366 return;
367 }
368 OnCommandReject(command_reject_view);
369 return;
370 }
371
372 case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
373 ConnectionParameterUpdateRequestView parameter_update_req_view =
374 ConnectionParameterUpdateRequestView::Create(control_packet_view);
375 if (!parameter_update_req_view.IsValid()) {
376 return;
377 }
378 OnConnectionParameterUpdateRequest(
379 parameter_update_req_view.GetIdentifier(), parameter_update_req_view.GetIntervalMin(),
380 parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(),
381 parameter_update_req_view.GetTimeoutMultiplier());
382 return;
383 }
384 case LeCommandCode::CONNECTION_PARAMETER_UPDATE_RESPONSE: {
385 ConnectionParameterUpdateResponseView parameter_update_rsp_view =
386 ConnectionParameterUpdateResponseView::Create(control_packet_view);
387 if (!parameter_update_rsp_view.IsValid()) {
388 return;
389 }
390 OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetIdentifier(),
391 parameter_update_rsp_view.GetResult());
392 return;
393 }
394 case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: {
395 LeCreditBasedConnectionRequestView connection_request_view =
396 LeCreditBasedConnectionRequestView::Create(control_packet_view);
397 if (!connection_request_view.IsValid()) {
398 return;
399 }
400 OnConnectionRequest(connection_request_view.GetIdentifier(), connection_request_view.GetLePsm(),
401 connection_request_view.GetSourceCid(), connection_request_view.GetMtu(),
402 connection_request_view.GetMps(), connection_request_view.GetInitialCredits());
403 return;
404 }
405 case LeCommandCode::LE_CREDIT_BASED_CONNECTION_RESPONSE: {
406 LeCreditBasedConnectionResponseView connection_response_view =
407 LeCreditBasedConnectionResponseView::Create(control_packet_view);
408 if (!connection_response_view.IsValid()) {
409 return;
410 }
411 OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
412 connection_response_view.GetMtu(), connection_response_view.GetMps(),
413 connection_response_view.GetInitialCredits(), connection_response_view.GetResult());
414 return;
415 }
416 case LeCommandCode::LE_FLOW_CONTROL_CREDIT: {
417 LeFlowControlCreditView credit_view = LeFlowControlCreditView::Create(control_packet_view);
418 if (!credit_view.IsValid()) {
419 return;
420 }
421 OnCredit(credit_view.GetCid(), credit_view.GetCredits());
422 return;
423 }
424 case LeCommandCode::DISCONNECTION_REQUEST: {
425 LeDisconnectionRequestView disconnection_request_view = LeDisconnectionRequestView::Create(control_packet_view);
426 if (!disconnection_request_view.IsValid()) {
427 return;
428 }
429 OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
430 disconnection_request_view.GetSourceCid());
431 return;
432 }
433 case LeCommandCode::DISCONNECTION_RESPONSE: {
434 LeDisconnectionResponseView disconnection_response_view =
435 LeDisconnectionResponseView::Create(control_packet_view);
436 if (!disconnection_response_view.IsValid()) {
437 return;
438 }
439 OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
440 disconnection_response_view.GetDestinationCid(),
441 disconnection_response_view.GetSourceCid());
442 return;
443 }
444 default:
445 LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
446 auto builder = LeCommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier());
447 enqueue_buffer_->Enqueue(std::move(builder), handler_);
448 return;
449 }
450 }
451
send_connection_response(SignalId signal_id,Cid local_cid,Mtu mtu,uint16_t mps,uint16_t initial_credit,LeCreditBasedConnectionResponseResult result)452 void LeSignallingManager::send_connection_response(SignalId signal_id, Cid local_cid, Mtu mtu, uint16_t mps,
453 uint16_t initial_credit,
454 LeCreditBasedConnectionResponseResult result) {
455 auto builder =
456 LeCreditBasedConnectionResponseBuilder::Create(signal_id.Value(), local_cid, mtu, mps, initial_credit, result);
457 enqueue_buffer_->Enqueue(std::move(builder), handler_);
458 }
459
on_command_timeout()460 void LeSignallingManager::on_command_timeout() {
461 LOG_WARN("Response time out");
462 if (command_just_sent_.signal_id_ == kInvalidSignalId) {
463 LOG_ERROR("No pending command");
464 return;
465 }
466 switch (command_just_sent_.command_code_) {
467 case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
468 link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_,
469 LeCreditBasedConnectionResponseResult::NO_RESOURCES_AVAILABLE);
470 break;
471 }
472 default:
473 break;
474 }
475 handle_send_next_command();
476 }
477
handle_send_next_command()478 void LeSignallingManager::handle_send_next_command() {
479 command_just_sent_.signal_id_ = kInvalidSignalId;
480 if (pending_commands_.empty()) {
481 return;
482 }
483
484 command_just_sent_ = pending_commands_.front();
485 pending_commands_.pop();
486 switch (command_just_sent_.command_code_) {
487 case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: {
488 auto builder = LeCreditBasedConnectionRequestBuilder::Create(
489 command_just_sent_.signal_id_.Value(), command_just_sent_.psm_, command_just_sent_.source_cid_,
490 command_just_sent_.mtu_, command_just_sent_.mps_, command_just_sent_.credits_);
491 enqueue_buffer_->Enqueue(std::move(builder), handler_);
492 alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
493 break;
494 }
495 case LeCommandCode::DISCONNECTION_REQUEST: {
496 auto builder = LeDisconnectionRequestBuilder::Create(
497 command_just_sent_.signal_id_.Value(), command_just_sent_.destination_cid_, command_just_sent_.source_cid_);
498 enqueue_buffer_->Enqueue(std::move(builder), handler_);
499 alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
500 break;
501 }
502 case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
503 auto builder = ConnectionParameterUpdateRequestBuilder::Create(
504 command_just_sent_.signal_id_.Value(), command_just_sent_.interval_min_, command_just_sent_.interval_max_,
505 command_just_sent_.slave_latency_, command_just_sent_.timeout_multiplier_);
506 enqueue_buffer_->Enqueue(std::move(builder), handler_);
507 alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
508 break;
509 }
510 default: {
511 LOG_WARN("Unsupported command code 0x%x", static_cast<int>(command_just_sent_.command_code_));
512 }
513 }
514 }
515 } // namespace internal
516 } // namespace le
517 } // namespace l2cap
518 } // namespace bluetooth
519