Loading system/gd/l2cap/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ filegroup { "classic/l2cap_classic_module.cc", "internal/basic_mode_channel_data_controller.cc", "internal/enhanced_retransmission_mode_channel_data_controller.cc", "internal/le_credit_based_channel_data_controller.cc", "internal/receiver.cc", "internal/scheduler_fifo.cc", "internal/sender.cc", Loading @@ -45,6 +46,7 @@ filegroup { "internal/basic_mode_channel_data_controller_test.cc", "internal/enhanced_retransmission_mode_channel_data_controller_test.cc", "internal/fixed_channel_allocator_test.cc", "internal/le_credit_based_channel_data_controller_test.cc", "internal/receiver_test.cc", "internal/scheduler_fifo_test.cc", "internal/sender_test.cc", Loading system/gd/l2cap/classic/cert/api.proto +26 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import "facade/common.proto"; service L2capClassicModuleCert { rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {} rpc SendIFrame(IFrame) returns (SendIFrameResult) {} rpc SendSFrame(SFrame) returns (SendSFrameResult) {} rpc SetupLink(SetupLinkRequest) returns (SetupLinkResponse) {} rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {} Loading @@ -33,6 +35,30 @@ message L2capPacket { bytes payload = 3; } message IFrame { facade.BluetoothAddress remote = 1; uint32 channel = 2; uint32 sar = 3; uint32 tx_seq = 4; uint32 req_seq = 5; uint32 f = 6; uint32 sdu_size = 7; bytes information = 8; } message SendIFrameResult {} message SFrame { facade.BluetoothAddress remote = 1; uint32 channel = 2; uint32 req_seq = 3; uint32 f = 4; uint32 p = 5; uint32 s = 6; } message SendSFrameResult {} message DisconnectLinkRequest { facade.BluetoothAddress remote = 1; } Loading system/gd/l2cap/classic/cert/cert.cc +31 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,37 @@ class L2capClassicModuleCertService : public L2capClassicModuleCert::Service { return ::grpc::Status::OK; } ::grpc::Status SendIFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::IFrame* request, ::bluetooth::l2cap::classic::cert::SendIFrameResult* response) override { std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(); auto req_string = request->information(); packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end())); std::unique_ptr<BasePacketBuilder> l2cap_builder; auto f = static_cast<Final>(request->f()); if (request->sar() == static_cast<int>(SegmentationAndReassembly::START)) { l2cap_builder = EnhancedInformationStartFrameBuilder::Create( request->channel(), request->tx_seq(), f, request->req_seq(), request->sdu_size(), std::move(packet)); } else { l2cap_builder = EnhancedInformationFrameBuilder::Create( request->channel(), request->tx_seq(), f, request->req_seq(), static_cast<SegmentationAndReassembly>(request->sar()), std::move(packet)); } outgoing_packet_queue_.push(std::move(l2cap_builder)); send_packet_from_queue(); return ::grpc::Status::OK; } ::grpc::Status SendSFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::SFrame* request, ::bluetooth::l2cap::classic::cert::SendSFrameResult* response) override { auto f = static_cast<Final>(request->f()); auto p = static_cast<Poll>(request->p()); auto s = static_cast<SupervisoryFunction>(request->s()); auto builder = EnhancedSupervisoryFrameBuilder::Create(request->channel(), s, p, f, request->req_seq()); outgoing_packet_queue_.push(std::move(builder)); send_packet_from_queue(); return ::grpc::Status::OK; } ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request, ::google::protobuf::Empty* response) override { auto builder = ConnectionRequestBuilder::Create(request->signal_id(), request->psm(), request->scid()); Loading system/gd/l2cap/classic/cert/simple_l2cap_test.py +4 −1 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ class SimpleL2capTest(GdBaseTestClass): log = log.data_packet if (log.channel == scid): log.payload = basic_frame_to_enhanced_information_frame(log.payload) self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=1, s=0)) data_received.append((log.channel, log.payload)) event_handler.on(lambda log : log.HasField("data_packet"), on_data_received) logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest()) Loading @@ -222,10 +223,12 @@ class SimpleL2capTest(GdBaseTestClass): assert (2, b"123") in data_received self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'*34)) self.cert_device.l2cap.SendIFrame(l2cap_cert_pb2.IFrame(channel=self.scid_dcid_map[scid], req_seq=1, tx_seq=0, sar=0, information=b"abcd")) logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest()) event_handler.execute(logs) assert (scid, b"abc"*34) in data_received self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest()) def test_connect_and_send_data(self): self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2)) Loading system/gd/l2cap/internal/le_credit_based_channel_data_controller.cc 0 → 100644 +112 −0 Original line number Diff line number Diff line /* * 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/internal/le_credit_based_channel_data_controller.h" #include "l2cap/l2cap_packets.h" #include "packet/fragmenting_inserter.h" #include "packet/raw_builder.h" namespace bluetooth { namespace l2cap { namespace internal { LeCreditBasedDataController::LeCreditBasedDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler, Scheduler* scheduler) : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler) { } void LeCreditBasedDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) { auto sdu_size = sdu->size(); if (sdu_size == 0) { LOG_WARN("Received empty SDU"); return; } if (sdu_size > mtu_) { LOG_WARN("Received sdu_size %d > mtu %d", static_cast<int>(sdu_size), mtu_); } std::vector<std::unique_ptr<packet::RawBuilder>> segments; // TODO: We don't need to waste 2 bytes for continuation segment. packet::FragmentingInserter fragmenting_inserter(mps_ - 2, std::back_insert_iterator(segments)); sdu->Serialize(fragmenting_inserter); fragmenting_inserter.finalize(); std::unique_ptr<BasicFrameBuilder> builder; builder = FirstLeInformationFrameBuilder::Create(remote_cid_, sdu_size, std::move(segments[0])); pdu_queue_.emplace(std::move(builder)); for (auto i = 1; i < segments.size(); i++) { builder = BasicFrameBuilder::Create(remote_cid_, std::move(segments[i])); pdu_queue_.emplace(std::move(builder)); } scheduler_->OnPacketsReady(cid_, segments.size()); } void LeCreditBasedDataController::OnPdu(packet::PacketView<true> pdu) { auto basic_frame_view = BasicFrameView::Create(pdu); if (!basic_frame_view.IsValid()) { LOG_WARN("Received invalid frame"); return; } if (basic_frame_view.size() > mps_) { LOG_WARN("Received frame size %d > mps %d, dropping the packet", static_cast<int>(basic_frame_view.size()), mps_); return; } if (remaining_sdu_continuation_packet_size_ == 0) { auto start_frame_view = FirstLeInformationFrameView::Create(basic_frame_view); if (!start_frame_view.IsValid()) { LOG_WARN("Received invalid frame"); return; } auto payload = start_frame_view.GetPayload(); auto sdu_size = start_frame_view.GetL2capSduLength(); remaining_sdu_continuation_packet_size_ = sdu_size - payload.size(); reassembly_stage_ = payload; } else { auto payload = basic_frame_view.GetPayload(); remaining_sdu_continuation_packet_size_ -= payload.size(); reassembly_stage_.AppendPacketView(payload); } if (remaining_sdu_continuation_packet_size_ == 0) { enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(reassembly_stage_), handler_); } else if (remaining_sdu_continuation_packet_size_ < 0 || reassembly_stage_.size() > mtu_) { LOG_WARN("Received larger SDU size than expected"); reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; // TODO: Close channel } } std::unique_ptr<packet::BasePacketBuilder> LeCreditBasedDataController::GetNextPacket() { auto next = std::move(pdu_queue_.front()); pdu_queue_.pop(); return next; } void LeCreditBasedDataController::SetMtu(Mtu mtu) { mtu_ = mtu; } void LeCreditBasedDataController::SetMps(uint16_t mps) { mps_ = mps; } void LeCreditBasedDataController::OnCredit(uint16_t credits) { int total_credits = credits_ + credits; credits_ = total_credits > 0xffff ? 0xffff : total_credits; } } // namespace internal } // namespace l2cap } // namespace bluetooth Loading
system/gd/l2cap/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ filegroup { "classic/l2cap_classic_module.cc", "internal/basic_mode_channel_data_controller.cc", "internal/enhanced_retransmission_mode_channel_data_controller.cc", "internal/le_credit_based_channel_data_controller.cc", "internal/receiver.cc", "internal/scheduler_fifo.cc", "internal/sender.cc", Loading @@ -45,6 +46,7 @@ filegroup { "internal/basic_mode_channel_data_controller_test.cc", "internal/enhanced_retransmission_mode_channel_data_controller_test.cc", "internal/fixed_channel_allocator_test.cc", "internal/le_credit_based_channel_data_controller_test.cc", "internal/receiver_test.cc", "internal/scheduler_fifo_test.cc", "internal/sender_test.cc", Loading
system/gd/l2cap/classic/cert/api.proto +26 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import "facade/common.proto"; service L2capClassicModuleCert { rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {} rpc SendIFrame(IFrame) returns (SendIFrameResult) {} rpc SendSFrame(SFrame) returns (SendSFrameResult) {} rpc SetupLink(SetupLinkRequest) returns (SetupLinkResponse) {} rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {} Loading @@ -33,6 +35,30 @@ message L2capPacket { bytes payload = 3; } message IFrame { facade.BluetoothAddress remote = 1; uint32 channel = 2; uint32 sar = 3; uint32 tx_seq = 4; uint32 req_seq = 5; uint32 f = 6; uint32 sdu_size = 7; bytes information = 8; } message SendIFrameResult {} message SFrame { facade.BluetoothAddress remote = 1; uint32 channel = 2; uint32 req_seq = 3; uint32 f = 4; uint32 p = 5; uint32 s = 6; } message SendSFrameResult {} message DisconnectLinkRequest { facade.BluetoothAddress remote = 1; } Loading
system/gd/l2cap/classic/cert/cert.cc +31 −0 Original line number Diff line number Diff line Loading @@ -80,6 +80,37 @@ class L2capClassicModuleCertService : public L2capClassicModuleCert::Service { return ::grpc::Status::OK; } ::grpc::Status SendIFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::IFrame* request, ::bluetooth::l2cap::classic::cert::SendIFrameResult* response) override { std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(); auto req_string = request->information(); packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end())); std::unique_ptr<BasePacketBuilder> l2cap_builder; auto f = static_cast<Final>(request->f()); if (request->sar() == static_cast<int>(SegmentationAndReassembly::START)) { l2cap_builder = EnhancedInformationStartFrameBuilder::Create( request->channel(), request->tx_seq(), f, request->req_seq(), request->sdu_size(), std::move(packet)); } else { l2cap_builder = EnhancedInformationFrameBuilder::Create( request->channel(), request->tx_seq(), f, request->req_seq(), static_cast<SegmentationAndReassembly>(request->sar()), std::move(packet)); } outgoing_packet_queue_.push(std::move(l2cap_builder)); send_packet_from_queue(); return ::grpc::Status::OK; } ::grpc::Status SendSFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::SFrame* request, ::bluetooth::l2cap::classic::cert::SendSFrameResult* response) override { auto f = static_cast<Final>(request->f()); auto p = static_cast<Poll>(request->p()); auto s = static_cast<SupervisoryFunction>(request->s()); auto builder = EnhancedSupervisoryFrameBuilder::Create(request->channel(), s, p, f, request->req_seq()); outgoing_packet_queue_.push(std::move(builder)); send_packet_from_queue(); return ::grpc::Status::OK; } ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request, ::google::protobuf::Empty* response) override { auto builder = ConnectionRequestBuilder::Create(request->signal_id(), request->psm(), request->scid()); Loading
system/gd/l2cap/classic/cert/simple_l2cap_test.py +4 −1 Original line number Diff line number Diff line Loading @@ -215,6 +215,7 @@ class SimpleL2capTest(GdBaseTestClass): log = log.data_packet if (log.channel == scid): log.payload = basic_frame_to_enhanced_information_frame(log.payload) self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=1, s=0)) data_received.append((log.channel, log.payload)) event_handler.on(lambda log : log.HasField("data_packet"), on_data_received) logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest()) Loading @@ -222,10 +223,12 @@ class SimpleL2capTest(GdBaseTestClass): assert (2, b"123") in data_received self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'*34)) self.cert_device.l2cap.SendIFrame(l2cap_cert_pb2.IFrame(channel=self.scid_dcid_map[scid], req_seq=1, tx_seq=0, sar=0, information=b"abcd")) logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest()) event_handler.execute(logs) assert (scid, b"abc"*34) in data_received self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest()) def test_connect_and_send_data(self): self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2)) Loading
system/gd/l2cap/internal/le_credit_based_channel_data_controller.cc 0 → 100644 +112 −0 Original line number Diff line number Diff line /* * 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/internal/le_credit_based_channel_data_controller.h" #include "l2cap/l2cap_packets.h" #include "packet/fragmenting_inserter.h" #include "packet/raw_builder.h" namespace bluetooth { namespace l2cap { namespace internal { LeCreditBasedDataController::LeCreditBasedDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler, Scheduler* scheduler) : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler) { } void LeCreditBasedDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) { auto sdu_size = sdu->size(); if (sdu_size == 0) { LOG_WARN("Received empty SDU"); return; } if (sdu_size > mtu_) { LOG_WARN("Received sdu_size %d > mtu %d", static_cast<int>(sdu_size), mtu_); } std::vector<std::unique_ptr<packet::RawBuilder>> segments; // TODO: We don't need to waste 2 bytes for continuation segment. packet::FragmentingInserter fragmenting_inserter(mps_ - 2, std::back_insert_iterator(segments)); sdu->Serialize(fragmenting_inserter); fragmenting_inserter.finalize(); std::unique_ptr<BasicFrameBuilder> builder; builder = FirstLeInformationFrameBuilder::Create(remote_cid_, sdu_size, std::move(segments[0])); pdu_queue_.emplace(std::move(builder)); for (auto i = 1; i < segments.size(); i++) { builder = BasicFrameBuilder::Create(remote_cid_, std::move(segments[i])); pdu_queue_.emplace(std::move(builder)); } scheduler_->OnPacketsReady(cid_, segments.size()); } void LeCreditBasedDataController::OnPdu(packet::PacketView<true> pdu) { auto basic_frame_view = BasicFrameView::Create(pdu); if (!basic_frame_view.IsValid()) { LOG_WARN("Received invalid frame"); return; } if (basic_frame_view.size() > mps_) { LOG_WARN("Received frame size %d > mps %d, dropping the packet", static_cast<int>(basic_frame_view.size()), mps_); return; } if (remaining_sdu_continuation_packet_size_ == 0) { auto start_frame_view = FirstLeInformationFrameView::Create(basic_frame_view); if (!start_frame_view.IsValid()) { LOG_WARN("Received invalid frame"); return; } auto payload = start_frame_view.GetPayload(); auto sdu_size = start_frame_view.GetL2capSduLength(); remaining_sdu_continuation_packet_size_ = sdu_size - payload.size(); reassembly_stage_ = payload; } else { auto payload = basic_frame_view.GetPayload(); remaining_sdu_continuation_packet_size_ -= payload.size(); reassembly_stage_.AppendPacketView(payload); } if (remaining_sdu_continuation_packet_size_ == 0) { enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(reassembly_stage_), handler_); } else if (remaining_sdu_continuation_packet_size_ < 0 || reassembly_stage_.size() > mtu_) { LOG_WARN("Received larger SDU size than expected"); reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; // TODO: Close channel } } std::unique_ptr<packet::BasePacketBuilder> LeCreditBasedDataController::GetNextPacket() { auto next = std::move(pdu_queue_.front()); pdu_queue_.pop(); return next; } void LeCreditBasedDataController::SetMtu(Mtu mtu) { mtu_ = mtu; } void LeCreditBasedDataController::SetMps(uint16_t mps) { mps_ = mps; } void LeCreditBasedDataController::OnCredit(uint16_t credits) { int total_credits = credits_ + credits; credits_ = total_credits > 0xffff ? 0xffff : total_credits; } } // namespace internal } // namespace l2cap } // namespace bluetooth