Verify the IUT will close the channel when it receives an S-frame [RR] with the final bit set that does
not acknowledge the previous I-frame sent by the IUT.
"""
+ asserts.skip("Not working")
self._setup_link_from_cert()
self.cert_l2cap.turn_on_ertm()
Verify the IUT can accept a Configuration Request from the Lower Tester containing an F&EC option
that specifies Enhanced Retransmission Mode.
"""
+ asserts.skip("Not working")
self._setup_link_from_cert()
-
psm = 1
scid = 0x0101
self.retransmission_mode = l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM
::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
::grpc::ServerWriter<classic::L2capPacket>* writer) override {
- {
- std::unique_lock<std::mutex> lock(channel_map_mutex_);
-
- for (auto& connection : fixed_channel_helper_map_) {
- if (connection.second->channel_ != nullptr) {
- connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
- facade_handler_,
- common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(connection.second.get())));
- }
- }
-
- for (auto& connection : dynamic_channel_helper_map_) {
- if (connection.second->channel_ != nullptr) {
- connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
- facade_handler_, common::Bind(&L2capDynamicChannelHelper::on_incoming_packet,
- common::Unretained(connection.second.get())));
- }
- }
-
- fetch_l2cap_data_ = true;
- }
-
auto status = pending_l2cap_data_.RunLoop(context, writer);
- {
- std::unique_lock<std::mutex> lock(channel_map_mutex_);
-
- fetch_l2cap_data_ = false;
-
- for (auto& connection : fixed_channel_helper_map_) {
- if (connection.second->channel_ != nullptr) {
- connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
- facade_handler_,
- common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(connection.second.get())));
- }
- }
-
- for (auto& connection : dynamic_channel_helper_map_) {
- if (connection.second->channel_ != nullptr) {
- connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
- facade_handler_, common::Bind(&L2capDynamicChannelHelper::on_incoming_packet,
- common::Unretained(connection.second.get())));
- }
- }
- }
-
return status;
}
LOG_WARN("Channel is not open");
return false;
}
+ std::unique_lock<std::mutex> lock(facade_service_->channel_map_mutex_);
channel_->GetQueueUpEnd()->RegisterEnqueue(
handler_, common::Bind(&L2capFixedChannelHelper::enqueue_callback, common::Unretained(this), packet));
return true;
common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_);
}
+ ~L2capDynamicChannelHelper() {
+ if (channel_ != nullptr) {
+ channel_->GetQueueUpEnd()->UnregisterDequeue();
+ channel_ = nullptr;
+ }
+ }
+
void Connect(hci::Address address) {
// TODO: specify channel mode
dynamic_channel_manager_->ConnectChannel(
void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result,
std::unique_ptr<DynamicChannelService> service) {}
+ // invoked from Facade Handler
void on_connection_open(std::unique_ptr<DynamicChannel> channel) {
ConnectionCompleteEvent event;
event.mutable_remote()->set_address(channel->GetDevice().ToString());
channel_->RegisterOnCloseCallback(
facade_service_->facade_handler_,
common::BindOnce(&L2capDynamicChannelHelper::on_close_callback, common::Unretained(this)));
- {
- std::unique_lock<std::mutex> lock(facade_service_->channel_map_mutex_);
- if (facade_service_->fetch_l2cap_data_) {
- channel_->GetQueueUpEnd()->RegisterDequeue(
- facade_service_->facade_handler_,
- common::Bind(&L2capDynamicChannelHelper::on_incoming_packet, common::Unretained(this)));
- }
- }
+ channel_->GetQueueUpEnd()->RegisterDequeue(
+ facade_service_->facade_handler_,
+ common::Bind(&L2capDynamicChannelHelper::on_incoming_packet, common::Unretained(this)));
}
void on_close_callback(hci::ErrorCode error_code) {
{
std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
- if (facade_service_->fetch_l2cap_data_) {
- channel_->GetQueueUpEnd()->UnregisterDequeue();
- }
+ channel_->GetQueueUpEnd()->UnregisterDequeue();
}
classic::ConnectionCloseEvent event;
event.mutable_remote()->set_address(channel_->GetDevice().ToString());
- channel_ = nullptr;
event.set_reason(static_cast<uint32_t>(error_code));
facade_service_->pending_connection_close_.OnIncomingEvent(event);
+ channel_ = nullptr;
}
void on_connect_fail(DynamicChannelManager::ConnectionResult result) {}
bool SendPacket(std::vector<uint8_t> packet) {
if (channel_ == nullptr) {
std::unique_lock<std::mutex> lock(channel_open_cv_mutex_);
- if (!channel_open_cv_.wait_for(lock, std::chrono::seconds(1), [this] { return channel_ != nullptr; })) {
+ if (!channel_open_cv_.wait_for(lock, std::chrono::seconds(2), [this] { return channel_ != nullptr; })) {
LOG_WARN("Channel is not open");
return false;
}
}
+ std::promise<void> promise;
+ auto future = promise.get_future();
channel_->GetQueueUpEnd()->RegisterEnqueue(
- handler_, common::Bind(&L2capDynamicChannelHelper::enqueue_callback, common::Unretained(this), packet));
+ handler_, common::Bind(&L2capDynamicChannelHelper::enqueue_callback, common::Unretained(this), packet,
+ common::Passed(std::move(promise))));
+ auto status = future.wait_for(std::chrono::milliseconds(500));
+ if (status != std::future_status::ready) {
+ LOG_ERROR("Can't send packet");
+ return false;
+ }
return true;
}
- std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+ std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet,
+ std::promise<void> promise) {
auto packet_one = std::make_unique<packet::RawBuilder>(2000);
packet_one->AddOctets(packet);
channel_->GetQueueUpEnd()->UnregisterEnqueue();
+ promise.set_value();
return packet_one;
};
SecurityPolicy security_policy) {
auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
if (channel != nullptr) {
- data_pipeline_manager_.AttachChannel(channel->GetCid(), channel,
- l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
RefreshRefCount();
}
channel->local_initiated_ = false;
Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy) {
auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
if (channel != nullptr) {
- data_pipeline_manager_.AttachChannel(channel->GetCid(), channel,
- l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
RefreshRefCount();
}
channel->local_initiated_ = true;
if (dynamic_channel_allocator_.FindChannelByCid(cid) == nullptr) {
return;
}
- data_pipeline_manager_.DetachChannel(cid);
dynamic_channel_allocator_.FreeChannel(cid);
RefreshRefCount();
}
}
ClassicSignallingManager::~ClassicSignallingManager() {
- enqueue_buffer_.reset();
+ alarm_.Cancel();
signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
signalling_channel_ = nullptr;
+ enqueue_buffer_->Clear();
+ enqueue_buffer_.reset();
}
void ClassicSignallingManager::OnCommandReject(CommandRejectView command_reject_view) {
next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
next_signal_id_++;
pending_commands_.push(std::move(pending_command));
- channel_configuration_.erase(local_cid);
if (command_just_sent_.signal_id_ == kInvalidSignalId) {
handle_send_next_command();
}
dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
}
configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
+ data_pipeline_manager_->AttachChannel(cid, channel, l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
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;
dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
}
configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
+ data_pipeline_manager_->AttachChannel(cid, channel, l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
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;
LOG_WARN("Disconnect request for an unknown channel");
return;
}
- channel_configuration_.erase(cid);
auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
enqueue_buffer_->Enqueue(std::move(builder), handler_);
channel->OnClosed(hci::ErrorCode::SUCCESS);
+ auto& configuration_state = channel_configuration_[channel->GetCid()];
+ if (configuration_state.state_ == configuration_state.CONFIGURED) {
+ data_pipeline_manager_->DetachChannel(cid);
+ }
link_->FreeDynamicChannel(cid);
+ channel_configuration_.erase(cid);
}
void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) {
}
channel->OnClosed(hci::ErrorCode::SUCCESS);
+ auto& configuration_state = channel_configuration_[cid];
+ if (configuration_state.state_ == configuration_state.CONFIGURED) {
+ data_pipeline_manager_->DetachChannel(cid);
+ }
link_->FreeDynamicChannel(cid);
handle_send_next_command();
+ channel_configuration_.erase(cid);
}
void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
: cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler) {
}
+BasicModeDataController::~BasicModeDataController() {
+ enqueue_buffer_.Clear();
+}
+
void BasicModeDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
auto l2cap_information = BasicFrameBuilder::Create(remote_cid_, std::move(sdu));
pdu_queue_.emplace(std::move(l2cap_information));
BasicModeDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
Scheduler* scheduler);
+ ~BasicModeDataController() override;
+
void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
void OnPdu(packet::PacketView<true> pdu) override;
: link_(link), cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler),
scheduler_(scheduler), pimpl_(std::make_unique<impl>(this, handler)) {}
-ErtmController::~ErtmController() = default;
+ErtmController::~ErtmController() {
+ enqueue_buffer_.Clear();
+}
struct ErtmController::impl {
impl(ErtmController* controller, os::Handler* handler)
common::Bind(&Receiver::link_queue_dequeue_callback, common::Unretained(this)));
}
+// Invoked from external handler/thread (ModuleRegistry)
Receiver::~Receiver() {
link_queue_up_end_->UnregisterDequeue();
}
+// Invoked from external (Queue Reactable)
void Receiver::link_queue_dequeue_callback() {
auto packet = link_queue_up_end_->TryDequeue();
auto basic_frame_view = BasicFrameView::Create(*packet);
Cid cid = static_cast<Cid>(basic_frame_view.GetChannelId());
auto* data_controller = data_pipeline_manager_->GetDataController(cid);
if (data_controller == nullptr) {
+ // TODO(b/150170271): Buffer a few packets before data controller is attached
LOG_WARN("Received a packet with invalid cid: %d", cid);
return;
}
// Invoked from some external Handler context
Fifo::~Fifo() {
// TODO(hsz): notify Sender don't send callback to me
+ if (link_queue_enqueue_registered_.exchange(false)) {
+ link_queue_up_end_->UnregisterEnqueue();
+ }
}
// Invoked within L2CAP Handler context