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