blob: 894de32da54d1d851553c80943b796f4c87a9c0f [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "l2cap/classic/internal/signalling_manager.h"
#include <chrono>
#include "common/bind.h"
#include "l2cap/classic/internal/channel_configuration_state.h"
#include "l2cap/classic/internal/link.h"
#include "l2cap/internal/data_pipeline_manager.h"
#include "l2cap/l2cap_packets.h"
#include "os/log.h"
#include "packet/raw_builder.h"
namespace bluetooth {
namespace l2cap {
namespace classic {
namespace internal {
static constexpr auto kTimeout = std::chrono::seconds(3);
ClassicSignallingManager::ClassicSignallingManager(os::Handler* handler, Link* link,
l2cap::internal::DataPipelineManager* data_pipeline_manager,
DynamicChannelServiceManagerImpl* dynamic_service_manager,
DynamicChannelAllocator* channel_allocator,
FixedChannelServiceManagerImpl* fixed_service_manager)
: handler_(handler), link_(link), data_pipeline_manager_(data_pipeline_manager),
dynamic_service_manager_(dynamic_service_manager), channel_allocator_(channel_allocator),
fixed_service_manager_(fixed_service_manager), alarm_(handler) {
ASSERT(handler_ != nullptr);
ASSERT(link_ != nullptr);
signalling_channel_ = link_->AllocateFixedChannel(kClassicSignallingCid, {});
signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
handler_, common::Bind(&ClassicSignallingManager::on_incoming_packet, common::Unretained(this)));
enqueue_buffer_ =
std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
}
ClassicSignallingManager::~ClassicSignallingManager() {
enqueue_buffer_.reset();
signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
signalling_channel_ = nullptr;
}
void ClassicSignallingManager::OnCommandReject(CommandRejectView command_reject_view) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected command reject: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
SignalId signal_id = command_reject_view.GetIdentifier();
if (last_sent_command.signal_id_ != signal_id) {
LOG_WARN("Unknown command reject");
return;
}
handle_send_next_command();
LOG_INFO("Command rejected");
}
void ClassicSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid) {
PendingCommand pending_command = {next_signal_id_, CommandCode::CONNECTION_REQUEST, psm, local_cid, {}, {}, {}};
next_signal_id_++;
pending_commands_.push(std::move(pending_command));
if (pending_commands_.size() == 1) {
handle_send_next_command();
}
}
void ClassicSignallingManager::SendConfigurationRequest(Cid remote_cid,
std::vector<std::unique_ptr<ConfigurationOption>> config) {
PendingCommand pending_command = {next_signal_id_, CommandCode::CONFIGURATION_REQUEST, {}, {}, remote_cid, {},
std::move(config)};
next_signal_id_++;
pending_commands_.push(std::move(pending_command));
if (pending_commands_.size() == 1) {
handle_send_next_command();
}
}
void ClassicSignallingManager::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
PendingCommand pending_command = {
next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
next_signal_id_++;
pending_commands_.push(std::move(pending_command));
if (pending_commands_.size() == 1) {
handle_send_next_command();
}
}
void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType type) {
PendingCommand pending_command = {next_signal_id_, CommandCode::INFORMATION_REQUEST, {}, {}, {}, type, {}};
next_signal_id_++;
pending_commands_.push(std::move(pending_command));
if (pending_commands_.size() == 1) {
handle_send_next_command();
}
}
void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload) {
LOG_WARN("Not supported");
}
void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) {
if (!IsPsmValid(psm)) {
LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
return;
}
if (remote_cid == kInvalidCid) {
LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::INVALID_CID,
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
return;
}
if (channel_allocator_->IsPsmUsed(psm)) {
LOG_WARN("Psm already exists");
send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
return;
}
if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
LOG_INFO("Service for this psm (%d) is not registered", psm);
send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
return;
}
auto new_channel = link_->AllocateDynamicChannel(psm, remote_cid, {});
if (new_channel == nullptr) {
LOG_WARN("Can't allocate dynamic channel");
return;
}
send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
auto& configuration_state = channel_configuration_[new_channel->GetCid()];
auto* service = dynamic_service_manager_->GetService(psm);
auto initial_config = service->GetConfigOption();
auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
mtu_configuration->mtu_ = initial_config.incoming_mtu;
configuration_state.incoming_mtu_ = initial_config.incoming_mtu;
auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
fcs_option->fcs_type_ = FcsType::DEFAULT;
if (!link_->GetRemoteSupportsFcs()) {
fcs_option->fcs_type_ = FcsType::NO_FCS;
configuration_state.fcs_type_ = FcsType::NO_FCS;
}
auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
if (!link_->GetRemoteSupportsErtm()) {
initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
}
switch (initial_config.channel_mode) {
case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
configuration_state.retransmission_and_flow_control_mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
break;
case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
retransmission_flow_control_configuration->mode_ =
RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
configuration_state.retransmission_and_flow_control_mode_ =
RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
// TODO: Decide where to put initial values
retransmission_flow_control_configuration->tx_window_size_ = 10;
retransmission_flow_control_configuration->max_transmit_ = 20;
retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
retransmission_flow_control_configuration->monitor_time_out_ = 12000;
retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
break;
}
configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;
std::vector<std::unique_ptr<ConfigurationOption>> config;
config.emplace_back(std::move(mtu_configuration));
config.emplace_back(std::move(retransmission_flow_control_configuration));
config.emplace_back(std::move(fcs_option));
SendConfigurationRequest(remote_cid, std::move(config));
}
void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid,
ConnectionResponseResult result, ConnectionResponseStatus status) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::CONNECTION_REQUEST) {
LOG_WARN("Received unexpected connection response");
return;
}
if (last_sent_command.source_cid_ != cid) {
LOG_WARN("SCID doesn't match: expected %d, received %d", last_sent_command.source_cid_, cid);
handle_send_next_command();
return;
}
if (result != ConnectionResponseResult::SUCCESS) {
handle_send_next_command();
return;
}
Psm pending_psm = last_sent_command.psm_;
auto new_channel = link_->AllocateReservedDynamicChannel(cid, pending_psm, remote_cid, {});
if (new_channel == nullptr) {
LOG_WARN("Can't allocate dynamic channel");
handle_send_next_command();
return;
}
alarm_.Cancel();
auto& configuration_state = channel_configuration_[new_channel->GetCid()];
auto initial_config = link_->GetConfigurationForInitialConfiguration(new_channel->GetCid());
auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
mtu_configuration->mtu_ = initial_config.incoming_mtu;
configuration_state.incoming_mtu_ = initial_config.incoming_mtu;
auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
fcs_option->fcs_type_ = FcsType::DEFAULT;
if (!link_->GetRemoteSupportsFcs()) {
fcs_option->fcs_type_ = FcsType::NO_FCS;
configuration_state.fcs_type_ = FcsType::NO_FCS;
}
auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
if (!link_->GetRemoteSupportsErtm()) {
initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
}
switch (initial_config.channel_mode) {
case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
configuration_state.retransmission_and_flow_control_mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
break;
case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
retransmission_flow_control_configuration->mode_ =
RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
configuration_state.retransmission_and_flow_control_mode_ =
RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
// TODO: Decide where to put initial values
retransmission_flow_control_configuration->tx_window_size_ = 10;
retransmission_flow_control_configuration->max_transmit_ = 20;
retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
retransmission_flow_control_configuration->monitor_time_out_ = 12000;
retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
break;
}
configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;
std::vector<std::unique_ptr<ConfigurationOption>> config;
config.emplace_back(std::move(mtu_configuration));
config.emplace_back(std::move(retransmission_flow_control_configuration));
config.emplace_back(std::move(fcs_option));
SendConfigurationRequest(remote_cid, {});
}
void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
std::vector<std::unique_ptr<ConfigurationOption>> options) {
auto channel = channel_allocator_->FindChannelByCid(cid);
if (channel == nullptr) {
LOG_WARN("Configuration request for an unknown channel");
return;
}
auto& configuration_state = channel_configuration_[cid];
for (auto& option : options) {
switch (option->type_) {
case ConfigurationOptionType::MTU: {
configuration_state.outgoing_mtu_ = MtuConfigurationOption::Specialize(option.get())->mtu_;
// TODO: If less than minimum (required by spec), reject
break;
}
case ConfigurationOptionType::FLUSH_TIMEOUT: {
// TODO: Handle this configuration option
break;
}
case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
configuration_state.remote_retransmission_and_flow_control_ = *config;
break;
}
case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
configuration_state.fcs_type_ = FrameCheckSequenceOption::Specialize(option.get())->fcs_type_;
break;
}
default:
LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
auto response =
ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
ConfigurationResponseResult::UNKNOWN_OPTIONS, {});
enqueue_buffer_->Enqueue(std::move(response), handler_);
return;
}
}
if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ) {
std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
if (channel->local_initiated_) {
link_->NotifyChannelCreation(cid, std::move(user_channel));
} else {
dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
}
configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
data_pipeline_manager_->UpdateClassicConfiguration(cid, configuration_state);
} else if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ_RSP) {
configuration_state.state_ = ChannelConfigurationState::State::WAIT_CONFIG_RSP;
}
auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
ConfigurationResponseResult::SUCCESS, {});
enqueue_buffer_->Enqueue(std::move(response), handler_);
}
void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
ConfigurationResponseResult result,
std::vector<std::unique_ptr<ConfigurationOption>> options) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
auto channel = channel_allocator_->FindChannelByCid(cid);
if (channel == nullptr) {
LOG_WARN("Configuration request for an unknown channel");
handle_send_next_command();
return;
}
// TODO: Handle status not SUCCESS
auto& configuration_state = channel_configuration_[channel->GetCid()];
for (auto& option : options) {
switch (option->type_) {
case ConfigurationOptionType::MTU: {
auto config = MtuConfigurationOption::Specialize(option.get());
configuration_state.incoming_mtu_ = config->mtu_;
break;
}
case ConfigurationOptionType::FLUSH_TIMEOUT: {
// TODO: Handle this configuration option
break;
}
case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
configuration_state.retransmission_and_flow_control_mode_ = config->mode_;
configuration_state.local_retransmission_and_flow_control_ = *config;
break;
}
case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
configuration_state.fcs_type_ = FrameCheckSequenceOption::Specialize(option.get())->fcs_type_;
break;
}
default:
LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
return;
}
}
if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_RSP) {
std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
if (channel->local_initiated_) {
link_->NotifyChannelCreation(cid, std::move(user_channel));
} else {
dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
}
configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
data_pipeline_manager_->UpdateClassicConfiguration(cid, configuration_state);
} else if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ_RSP) {
configuration_state.state_ = ChannelConfigurationState::State::WAIT_CONFIG_REQ;
}
alarm_.Cancel();
handle_send_next_command();
}
void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
// TODO: check cid match
auto channel = channel_allocator_->FindChannelByCid(cid);
if (channel == nullptr) {
LOG_WARN("Disconnect request for an unknown channel");
return;
}
auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
channel->OnClosed(hci::ErrorCode::SUCCESS);
link_->FreeDynamicChannel(cid);
handle_send_next_command();
}
void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
alarm_.Cancel();
if (last_sent_command.signal_id_ != signal_id ||
last_sent_command.command_code_ != CommandCode::DISCONNECTION_REQUEST) {
return;
}
auto channel = channel_allocator_->FindChannelByCid(cid);
if (channel == nullptr) {
LOG_WARN("Disconnect response for an unknown channel");
handle_send_next_command();
return;
}
channel->OnClosed(hci::ErrorCode::SUCCESS);
link_->FreeDynamicChannel(cid);
handle_send_next_command();
}
void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
std::vector<uint8_t> packet_vector{packet.begin(), packet.end()};
auto raw_builder = std::make_unique<packet::RawBuilder>();
raw_builder->AddOctets(packet_vector);
auto builder = EchoResponseBuilder::Create(signal_id.Value(), std::move(raw_builder));
enqueue_buffer_->Enqueue(std::move(builder), handler_);
handle_send_next_command();
}
void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::ECHO_REQUEST) {
return;
}
LOG_INFO("Echo response received");
alarm_.Cancel();
handle_send_next_command();
}
void ClassicSignallingManager::OnInformationRequest(SignalId signal_id, InformationRequestInfoType type) {
switch (type) {
case InformationRequestInfoType::CONNECTIONLESS_MTU: {
auto response = InformationResponseConnectionlessMtuBuilder::Create(
signal_id.Value(), InformationRequestResult::SUCCESS, kDefaultClassicMtu);
enqueue_buffer_->Enqueue(std::move(response), handler_);
break;
}
case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
// TODO: implement this response
auto response = InformationResponseExtendedFeaturesBuilder::Create(
signal_id.Value(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
enqueue_buffer_->Enqueue(std::move(response), handler_);
break;
}
case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
auto response = InformationResponseFixedChannelsBuilder::Create(
signal_id.Value(), InformationRequestResult::SUCCESS, fixed_service_manager_->GetSupportedFixedChannelMask());
enqueue_buffer_->Enqueue(std::move(response), handler_);
break;
}
}
}
void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& response) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
if (last_sent_command.signal_id_ != signal_id ||
last_sent_command.command_code_ != CommandCode::INFORMATION_REQUEST) {
return;
}
auto type = response.GetInfoType();
switch (type) {
case InformationRequestInfoType::CONNECTIONLESS_MTU: {
auto view = InformationResponseConnectionlessMtuView::Create(response);
if (!view.IsValid()) {
LOG_WARN("Invalid InformationResponseConnectionlessMtu received");
return;
}
link_->SetRemoteConnectionlessMtu(view.GetConnectionlessMtu());
break;
}
case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
auto view = InformationResponseExtendedFeaturesView::Create(response);
if (!view.IsValid()) {
LOG_WARN("Invalid InformationResponseExtendedFeatures received");
return;
}
link_->SetRemoteSupportsErtm((view.GetEnhancedRetransmissionMode()));
link_->SetRemoteSupportsFcs(view.GetFcsOption());
// We don't care about other parameters
break;
}
case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
auto view = InformationResponseFixedChannelsView::Create(response);
if (!view.IsValid()) {
LOG_WARN("Invalid InformationResponseFixedChannel received");
return;
}
// We don't use fixed channels (connectionless or BR/EDR security) for now so we don't care
break;
}
}
alarm_.Cancel();
handle_send_next_command();
}
void ClassicSignallingManager::on_incoming_packet() {
auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
ControlView control_packet_view = ControlView::Create(*packet);
if (!control_packet_view.IsValid()) {
LOG_WARN("Invalid signalling packet received");
return;
}
auto code = control_packet_view.GetCode();
switch (code) {
case CommandCode::COMMAND_REJECT: {
CommandRejectView command_reject_view = CommandRejectView::Create(control_packet_view);
if (!command_reject_view.IsValid()) {
return;
}
OnCommandReject(command_reject_view);
return;
}
case CommandCode::CONNECTION_REQUEST: {
ConnectionRequestView connection_request_view = ConnectionRequestView::Create(control_packet_view);
if (!connection_request_view.IsValid()) {
return;
}
OnConnectionRequest(control_packet_view.GetIdentifier(), connection_request_view.GetPsm(),
connection_request_view.GetSourceCid());
return;
}
case CommandCode::CONNECTION_RESPONSE: {
ConnectionResponseView connection_response_view = ConnectionResponseView::Create(control_packet_view);
if (!connection_response_view.IsValid()) {
return;
}
OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
connection_response_view.GetSourceCid(), connection_response_view.GetResult(),
connection_response_view.GetStatus());
return;
}
case CommandCode::CONFIGURATION_REQUEST: {
ConfigurationRequestView configuration_request_view = ConfigurationRequestView::Create(control_packet_view);
if (!configuration_request_view.IsValid()) {
return;
}
OnConfigurationRequest(configuration_request_view.GetIdentifier(), configuration_request_view.GetDestinationCid(),
configuration_request_view.GetContinuation(), configuration_request_view.GetConfig());
return;
}
case CommandCode::CONFIGURATION_RESPONSE: {
ConfigurationResponseView configuration_response_view = ConfigurationResponseView::Create(control_packet_view);
if (!configuration_response_view.IsValid()) {
return;
}
OnConfigurationResponse(configuration_response_view.GetIdentifier(), configuration_response_view.GetSourceCid(),
configuration_response_view.GetContinuation(), configuration_response_view.GetResult(),
configuration_response_view.GetConfig());
return;
}
case CommandCode::DISCONNECTION_REQUEST: {
DisconnectionRequestView disconnection_request_view = DisconnectionRequestView::Create(control_packet_view);
if (!disconnection_request_view.IsValid()) {
return;
}
OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
disconnection_request_view.GetSourceCid());
return;
}
case CommandCode::DISCONNECTION_RESPONSE: {
DisconnectionResponseView disconnection_response_view = DisconnectionResponseView::Create(control_packet_view);
if (!disconnection_response_view.IsValid()) {
return;
}
OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
disconnection_response_view.GetDestinationCid(),
disconnection_response_view.GetSourceCid());
return;
}
case CommandCode::ECHO_REQUEST: {
EchoRequestView echo_request_view = EchoRequestView::Create(control_packet_view);
if (!echo_request_view.IsValid()) {
return;
}
OnEchoRequest(echo_request_view.GetIdentifier(), echo_request_view.GetPayload());
return;
}
case CommandCode::ECHO_RESPONSE: {
EchoResponseView echo_response_view = EchoResponseView::Create(control_packet_view);
if (!echo_response_view.IsValid()) {
return;
}
OnEchoResponse(echo_response_view.GetIdentifier(), echo_response_view.GetPayload());
return;
}
case CommandCode::INFORMATION_REQUEST: {
InformationRequestView information_request_view = InformationRequestView::Create(control_packet_view);
if (!information_request_view.IsValid()) {
return;
}
OnInformationRequest(information_request_view.GetIdentifier(), information_request_view.GetInfoType());
return;
}
case CommandCode::INFORMATION_RESPONSE: {
InformationResponseView information_response_view = InformationResponseView::Create(control_packet_view);
if (!information_response_view.IsValid()) {
return;
}
OnInformationResponse(information_response_view.GetIdentifier(), information_response_view);
return;
}
default:
LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
auto builder = CommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier());
enqueue_buffer_->Enqueue(std::move(builder), handler_);
return;
}
}
void ClassicSignallingManager::send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid,
ConnectionResponseResult result,
ConnectionResponseStatus status) {
auto builder = ConnectionResponseBuilder::Create(signal_id.Value(), local_cid, remote_cid, result, status);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
}
void ClassicSignallingManager::on_command_timeout() {
LOG_WARN("Response time out");
if (pending_commands_.empty()) {
LOG_ERROR("No pending command");
return;
}
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
switch (last_sent_command.command_code_) {
case CommandCode::CONFIGURATION_REQUEST: {
SendDisconnectionRequest(last_sent_command.source_cid_, last_sent_command.destination_cid_);
break;
}
default:
break;
}
handle_send_next_command();
}
void ClassicSignallingManager::handle_send_next_command() {
if (pending_commands_.empty()) {
return;
}
auto& last_sent_command = pending_commands_.front();
auto signal_id = last_sent_command.signal_id_;
auto psm = last_sent_command.psm_;
auto source_cid = last_sent_command.source_cid_;
auto destination_cid = last_sent_command.destination_cid_;
auto info_type = last_sent_command.info_type_;
auto config = std::move(last_sent_command.config_);
switch (last_sent_command.command_code_) {
case CommandCode::CONNECTION_REQUEST: {
auto builder = ConnectionRequestBuilder::Create(signal_id.Value(), psm, source_cid);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
kTimeout);
break;
}
case CommandCode::CONFIGURATION_REQUEST: {
auto builder =
ConfigurationRequestBuilder::Create(signal_id.Value(), destination_cid, Continuation::END, std::move(config));
enqueue_buffer_->Enqueue(std::move(builder), handler_);
alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
kTimeout);
break;
}
case CommandCode::DISCONNECTION_REQUEST: {
auto builder = DisconnectionRequestBuilder::Create(signal_id.Value(), destination_cid, source_cid);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
kTimeout);
break;
}
case CommandCode::INFORMATION_REQUEST: {
auto builder = InformationRequestBuilder::Create(signal_id.Value(), info_type);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
kTimeout);
break;
}
default:
LOG_WARN("Unsupported command code 0x%x", static_cast<int>(last_sent_command.command_code_));
}
}
} // namespace internal
} // namespace classic
} // namespace l2cap
} // namespace bluetooth