Loading system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc +56 −13 Original line number Original line Diff line number Diff line Loading @@ -168,20 +168,20 @@ struct ErtmController::impl { } } } } void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar, void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<true>& payload) { const packet::PacketView<true>& payload) { if (rx_state_ == RxState::RECV) { if (rx_state_ == RxState::RECV) { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) { !local_busy()) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); send_ack(Final::NOT_SET); send_ack(Final::NOT_SET); } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) { with_valid_f_bit(f) && !local_busy()) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); if (!rej_actioned_) { if (!rej_actioned_) { retransmit_i_frames(req_seq); retransmit_i_frames(req_seq); send_pending_i_frames(); send_pending_i_frames(); Loading Loading @@ -216,14 +216,14 @@ struct ErtmController::impl { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); send_ack(Final::NOT_SET); send_ack(Final::NOT_SET); rx_state_ = RxState::RECV; rx_state_ = RxState::RECV; } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { with_valid_f_bit(f)) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); if (!rej_actioned_) { if (!rej_actioned_) { retransmit_i_frames(req_seq); retransmit_i_frames(req_seq); send_pending_i_frames(); send_pending_i_frames(); Loading Loading @@ -682,8 +682,8 @@ struct ErtmController::impl { recv_f_bit(f); recv_f_bit(f); } } void data_indication(SegmentationAndReassembly sar, const packet::PacketView<true>& segment) { void data_indication(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<true>& segment) { controller_->stage_for_reassembly(sar, segment); controller_->stage_for_reassembly(sar, sdu_size, segment); buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin; buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin; } } Loading Loading @@ -825,8 +825,21 @@ void ErtmController::on_pdu_no_fcs(const packet::PacketView<true>& pdu) { LOG_WARN("Received invalid frame"); LOG_WARN("Received invalid frame"); return; return; } } pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(), Final f = i_frame_view.GetF(); i_frame_view.GetPayload()); uint8_t tx_seq = i_frame_view.GetTxSeq(); uint8_t req_seq = i_frame_view.GetReqSeq(); auto sar = i_frame_view.GetSar(); if (sar == SegmentationAndReassembly::START) { auto i_frame_start_view = EnhancedInformationStartFrameView::Create(i_frame_view); if (!i_frame_start_view.IsValid()) { LOG_WARN("Received invalid I-Frame START"); return; } pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(), i_frame_start_view.GetPayload()); } else { pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload()); } } else if (type == FrameType::S_FRAME) { } else if (type == FrameType::S_FRAME) { auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view); auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view); if (!s_frame_view.IsValid()) { if (!s_frame_view.IsValid()) { Loading Loading @@ -872,8 +885,21 @@ void ErtmController::on_pdu_fcs(const packet::PacketView<true>& pdu) { LOG_WARN("Received invalid frame"); LOG_WARN("Received invalid frame"); return; return; } } pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(), Final f = i_frame_view.GetF(); i_frame_view.GetPayload()); uint8_t tx_seq = i_frame_view.GetTxSeq(); uint8_t req_seq = i_frame_view.GetReqSeq(); auto sar = i_frame_view.GetSar(); if (sar == SegmentationAndReassembly::START) { auto i_frame_start_view = EnhancedInformationStartFrameWithFcsView::Create(i_frame_view); if (!i_frame_start_view.IsValid()) { LOG_WARN("Received invalid I-Frame START"); return; } pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(), i_frame_start_view.GetPayload()); } else { pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload()); } } else if (type == FrameType::S_FRAME) { } else if (type == FrameType::S_FRAME) { auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view); auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view); if (!s_frame_view.IsValid()) { if (!s_frame_view.IsValid()) { Loading Loading @@ -908,10 +934,16 @@ std::unique_ptr<packet::BasePacketBuilder> ErtmController::GetNextPacket() { return next; return next; } } void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<kLittleEndian>& payload) { const packet::PacketView<kLittleEndian>& payload) { switch (sar) { switch (sar) { case SegmentationAndReassembly::UNSEGMENTED: case SegmentationAndReassembly::UNSEGMENTED: if (sar_state_ != SegmentationAndReassembly::END) { LOG_WARN("Received invalid SAR"); close_channel(); return; } // TODO: Enforce MTU enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_); break; break; case SegmentationAndReassembly::START: case SegmentationAndReassembly::START: Loading @@ -920,8 +952,10 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, close_channel(); close_channel(); return; return; } } // TODO: Enforce MTU sar_state_ = SegmentationAndReassembly::START; sar_state_ = SegmentationAndReassembly::START; reassembly_stage_ = payload; reassembly_stage_ = payload; remaining_sdu_continuation_packet_size_ = sdu_size - payload.size(); break; break; case SegmentationAndReassembly::CONTINUATION: case SegmentationAndReassembly::CONTINUATION: if (sar_state_ == SegmentationAndReassembly::END) { if (sar_state_ == SegmentationAndReassembly::END) { Loading @@ -930,6 +964,7 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, return; return; } } reassembly_stage_.AppendPacketView(payload); reassembly_stage_.AppendPacketView(payload); remaining_sdu_continuation_packet_size_ -= payload.size(); break; break; case SegmentationAndReassembly::END: case SegmentationAndReassembly::END: if (sar_state_ == SegmentationAndReassembly::END) { if (sar_state_ == SegmentationAndReassembly::END) { Loading @@ -937,9 +972,17 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, close_channel(); close_channel(); return; return; } } sar_state_ = SegmentationAndReassembly::END; remaining_sdu_continuation_packet_size_ -= payload.size(); if (remaining_sdu_continuation_packet_size_ != 0) { LOG_WARN("Received invalid END I-Frame"); reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; close_channel(); return; } reassembly_stage_.AppendPacketView(payload); reassembly_stage_.AppendPacketView(payload); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_); sar_state_ = SegmentationAndReassembly::END; break; break; } } } } Loading system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h +15 −13 Original line number Original line Diff line number Diff line Loading @@ -59,7 +59,19 @@ class ErtmController : public DataController { os::Handler* handler_; os::Handler* handler_; std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_; std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_; Scheduler* scheduler_; Scheduler* scheduler_; // Configuration options bool fcs_enabled_ = false; bool fcs_enabled_ = false; uint16_t local_tx_window_ = 10; uint16_t local_max_transmit_ = 20; uint16_t local_retransmit_timeout_ms_ = 2000; uint16_t local_monitor_timeout_ms_ = 12000; uint16_t remote_tx_window_ = 10; uint16_t remote_mps_ = 1010; uint16_t size_each_packet_ = (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */); class PacketViewForReassembly : public packet::PacketView<kLittleEndian> { class PacketViewForReassembly : public packet::PacketView<kLittleEndian> { public: public: Loading @@ -83,8 +95,10 @@ class ErtmController : public DataController { PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()}; PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()}; SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END; SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END; uint16_t remaining_sdu_continuation_packet_size_ = 0; void stage_for_reassembly(SegmentationAndReassembly sar, const packet::PacketView<kLittleEndian>& payload); void stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<kLittleEndian>& payload); void send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu); void send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu); void close_channel(); void close_channel(); Loading @@ -92,18 +106,6 @@ class ErtmController : public DataController { void on_pdu_no_fcs(const packet::PacketView<true>& pdu); void on_pdu_no_fcs(const packet::PacketView<true>& pdu); void on_pdu_fcs(const packet::PacketView<true>& pdu); void on_pdu_fcs(const packet::PacketView<true>& pdu); // Configuration options uint16_t local_tx_window_ = 10; uint16_t local_max_transmit_ = 20; uint16_t local_retransmit_timeout_ms_ = 2000; uint16_t local_monitor_timeout_ms_ = 12000; uint16_t remote_tx_window_ = 10; uint16_t remote_mps_ = 1010; uint16_t size_each_packet_ = (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */); struct impl; struct impl; std::unique_ptr<impl> pimpl_; std::unique_ptr<impl> pimpl_; }; }; Loading system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc +48 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,54 @@ TEST_F(ErtmDataControllerTest, receive_no_fcs) { EXPECT_EQ(data, "abcd"); EXPECT_EQ(data, "abcd"); } } TEST_F(ErtmDataControllerTest, reassemble_valid_sdu) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler}; auto segment1 = CreateSdu({'a'}); auto segment2 = CreateSdu({'b', 'c'}); auto segment3 = CreateSdu({'d', 'e', 'f'}); auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 6, std::move(segment1)); auto base_view = GetPacketView(std::move(builder1)); controller.OnPdu(base_view); auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0, SegmentationAndReassembly::CONTINUATION, std::move(segment2)); base_view = GetPacketView(std::move(builder2)); controller.OnPdu(base_view); auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END, std::move(segment3)); base_view = GetPacketView(std::move(builder3)); controller.OnPdu(base_view); sync_handler(queue_handler_); auto payload = channel_queue.GetUpEnd()->TryDequeue(); EXPECT_NE(payload, nullptr); std::string data = std::string(payload->begin(), payload->end()); EXPECT_EQ(data, "abcdef"); } TEST_F(ErtmDataControllerTest, reassemble_invalid_sdu_size_in_start_frame) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler}; auto segment1 = CreateSdu({'a'}); auto segment2 = CreateSdu({'b', 'c'}); auto segment3 = CreateSdu({'d', 'e', 'f'}); auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 10, std::move(segment1)); auto base_view = GetPacketView(std::move(builder1)); controller.OnPdu(base_view); auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0, SegmentationAndReassembly::CONTINUATION, std::move(segment2)); base_view = GetPacketView(std::move(builder2)); controller.OnPdu(base_view); auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END, std::move(segment3)); base_view = GetPacketView(std::move(builder3)); controller.OnPdu(base_view); sync_handler(queue_handler_); auto payload = channel_queue.GetUpEnd()->TryDequeue(); EXPECT_EQ(payload, nullptr); } TEST_F(ErtmDataControllerTest, transmit_with_fcs) { TEST_F(ErtmDataControllerTest, transmit_with_fcs) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; testing::MockScheduler scheduler; Loading Loading
system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc +56 −13 Original line number Original line Diff line number Diff line Loading @@ -168,20 +168,20 @@ struct ErtmController::impl { } } } } void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar, void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<true>& payload) { const packet::PacketView<true>& payload) { if (rx_state_ == RxState::RECV) { if (rx_state_ == RxState::RECV) { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) { !local_busy()) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); send_ack(Final::NOT_SET); send_ack(Final::NOT_SET); } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) { with_valid_f_bit(f) && !local_busy()) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); if (!rej_actioned_) { if (!rej_actioned_) { retransmit_i_frames(req_seq); retransmit_i_frames(req_seq); send_pending_i_frames(); send_pending_i_frames(); Loading Loading @@ -216,14 +216,14 @@ struct ErtmController::impl { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); send_ack(Final::NOT_SET); send_ack(Final::NOT_SET); rx_state_ = RxState::RECV; rx_state_ = RxState::RECV; } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) { with_valid_f_bit(f)) { increment_expected_tx_seq(); increment_expected_tx_seq(); pass_to_tx(req_seq, f); pass_to_tx(req_seq, f); data_indication(sar, payload); data_indication(sar, sdu_size, payload); if (!rej_actioned_) { if (!rej_actioned_) { retransmit_i_frames(req_seq); retransmit_i_frames(req_seq); send_pending_i_frames(); send_pending_i_frames(); Loading Loading @@ -682,8 +682,8 @@ struct ErtmController::impl { recv_f_bit(f); recv_f_bit(f); } } void data_indication(SegmentationAndReassembly sar, const packet::PacketView<true>& segment) { void data_indication(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<true>& segment) { controller_->stage_for_reassembly(sar, segment); controller_->stage_for_reassembly(sar, sdu_size, segment); buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin; buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin; } } Loading Loading @@ -825,8 +825,21 @@ void ErtmController::on_pdu_no_fcs(const packet::PacketView<true>& pdu) { LOG_WARN("Received invalid frame"); LOG_WARN("Received invalid frame"); return; return; } } pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(), Final f = i_frame_view.GetF(); i_frame_view.GetPayload()); uint8_t tx_seq = i_frame_view.GetTxSeq(); uint8_t req_seq = i_frame_view.GetReqSeq(); auto sar = i_frame_view.GetSar(); if (sar == SegmentationAndReassembly::START) { auto i_frame_start_view = EnhancedInformationStartFrameView::Create(i_frame_view); if (!i_frame_start_view.IsValid()) { LOG_WARN("Received invalid I-Frame START"); return; } pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(), i_frame_start_view.GetPayload()); } else { pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload()); } } else if (type == FrameType::S_FRAME) { } else if (type == FrameType::S_FRAME) { auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view); auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view); if (!s_frame_view.IsValid()) { if (!s_frame_view.IsValid()) { Loading Loading @@ -872,8 +885,21 @@ void ErtmController::on_pdu_fcs(const packet::PacketView<true>& pdu) { LOG_WARN("Received invalid frame"); LOG_WARN("Received invalid frame"); return; return; } } pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(), Final f = i_frame_view.GetF(); i_frame_view.GetPayload()); uint8_t tx_seq = i_frame_view.GetTxSeq(); uint8_t req_seq = i_frame_view.GetReqSeq(); auto sar = i_frame_view.GetSar(); if (sar == SegmentationAndReassembly::START) { auto i_frame_start_view = EnhancedInformationStartFrameWithFcsView::Create(i_frame_view); if (!i_frame_start_view.IsValid()) { LOG_WARN("Received invalid I-Frame START"); return; } pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(), i_frame_start_view.GetPayload()); } else { pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload()); } } else if (type == FrameType::S_FRAME) { } else if (type == FrameType::S_FRAME) { auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view); auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view); if (!s_frame_view.IsValid()) { if (!s_frame_view.IsValid()) { Loading Loading @@ -908,10 +934,16 @@ std::unique_ptr<packet::BasePacketBuilder> ErtmController::GetNextPacket() { return next; return next; } } void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<kLittleEndian>& payload) { const packet::PacketView<kLittleEndian>& payload) { switch (sar) { switch (sar) { case SegmentationAndReassembly::UNSEGMENTED: case SegmentationAndReassembly::UNSEGMENTED: if (sar_state_ != SegmentationAndReassembly::END) { LOG_WARN("Received invalid SAR"); close_channel(); return; } // TODO: Enforce MTU enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_); break; break; case SegmentationAndReassembly::START: case SegmentationAndReassembly::START: Loading @@ -920,8 +952,10 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, close_channel(); close_channel(); return; return; } } // TODO: Enforce MTU sar_state_ = SegmentationAndReassembly::START; sar_state_ = SegmentationAndReassembly::START; reassembly_stage_ = payload; reassembly_stage_ = payload; remaining_sdu_continuation_packet_size_ = sdu_size - payload.size(); break; break; case SegmentationAndReassembly::CONTINUATION: case SegmentationAndReassembly::CONTINUATION: if (sar_state_ == SegmentationAndReassembly::END) { if (sar_state_ == SegmentationAndReassembly::END) { Loading @@ -930,6 +964,7 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, return; return; } } reassembly_stage_.AppendPacketView(payload); reassembly_stage_.AppendPacketView(payload); remaining_sdu_continuation_packet_size_ -= payload.size(); break; break; case SegmentationAndReassembly::END: case SegmentationAndReassembly::END: if (sar_state_ == SegmentationAndReassembly::END) { if (sar_state_ == SegmentationAndReassembly::END) { Loading @@ -937,9 +972,17 @@ void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, close_channel(); close_channel(); return; return; } } sar_state_ = SegmentationAndReassembly::END; remaining_sdu_continuation_packet_size_ -= payload.size(); if (remaining_sdu_continuation_packet_size_ != 0) { LOG_WARN("Received invalid END I-Frame"); reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>()); remaining_sdu_continuation_packet_size_ = 0; close_channel(); return; } reassembly_stage_.AppendPacketView(payload); reassembly_stage_.AppendPacketView(payload); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_); enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_); sar_state_ = SegmentationAndReassembly::END; break; break; } } } } Loading
system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h +15 −13 Original line number Original line Diff line number Diff line Loading @@ -59,7 +59,19 @@ class ErtmController : public DataController { os::Handler* handler_; os::Handler* handler_; std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_; std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_; Scheduler* scheduler_; Scheduler* scheduler_; // Configuration options bool fcs_enabled_ = false; bool fcs_enabled_ = false; uint16_t local_tx_window_ = 10; uint16_t local_max_transmit_ = 20; uint16_t local_retransmit_timeout_ms_ = 2000; uint16_t local_monitor_timeout_ms_ = 12000; uint16_t remote_tx_window_ = 10; uint16_t remote_mps_ = 1010; uint16_t size_each_packet_ = (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */); class PacketViewForReassembly : public packet::PacketView<kLittleEndian> { class PacketViewForReassembly : public packet::PacketView<kLittleEndian> { public: public: Loading @@ -83,8 +95,10 @@ class ErtmController : public DataController { PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()}; PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()}; SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END; SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END; uint16_t remaining_sdu_continuation_packet_size_ = 0; void stage_for_reassembly(SegmentationAndReassembly sar, const packet::PacketView<kLittleEndian>& payload); void stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<kLittleEndian>& payload); void send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu); void send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu); void close_channel(); void close_channel(); Loading @@ -92,18 +106,6 @@ class ErtmController : public DataController { void on_pdu_no_fcs(const packet::PacketView<true>& pdu); void on_pdu_no_fcs(const packet::PacketView<true>& pdu); void on_pdu_fcs(const packet::PacketView<true>& pdu); void on_pdu_fcs(const packet::PacketView<true>& pdu); // Configuration options uint16_t local_tx_window_ = 10; uint16_t local_max_transmit_ = 20; uint16_t local_retransmit_timeout_ms_ = 2000; uint16_t local_monitor_timeout_ms_ = 12000; uint16_t remote_tx_window_ = 10; uint16_t remote_mps_ = 1010; uint16_t size_each_packet_ = (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */); struct impl; struct impl; std::unique_ptr<impl> pimpl_; std::unique_ptr<impl> pimpl_; }; }; Loading
system/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc +48 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,54 @@ TEST_F(ErtmDataControllerTest, receive_no_fcs) { EXPECT_EQ(data, "abcd"); EXPECT_EQ(data, "abcd"); } } TEST_F(ErtmDataControllerTest, reassemble_valid_sdu) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler}; auto segment1 = CreateSdu({'a'}); auto segment2 = CreateSdu({'b', 'c'}); auto segment3 = CreateSdu({'d', 'e', 'f'}); auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 6, std::move(segment1)); auto base_view = GetPacketView(std::move(builder1)); controller.OnPdu(base_view); auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0, SegmentationAndReassembly::CONTINUATION, std::move(segment2)); base_view = GetPacketView(std::move(builder2)); controller.OnPdu(base_view); auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END, std::move(segment3)); base_view = GetPacketView(std::move(builder3)); controller.OnPdu(base_view); sync_handler(queue_handler_); auto payload = channel_queue.GetUpEnd()->TryDequeue(); EXPECT_NE(payload, nullptr); std::string data = std::string(payload->begin(), payload->end()); EXPECT_EQ(data, "abcdef"); } TEST_F(ErtmDataControllerTest, reassemble_invalid_sdu_size_in_start_frame) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler}; auto segment1 = CreateSdu({'a'}); auto segment2 = CreateSdu({'b', 'c'}); auto segment3 = CreateSdu({'d', 'e', 'f'}); auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 10, std::move(segment1)); auto base_view = GetPacketView(std::move(builder1)); controller.OnPdu(base_view); auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0, SegmentationAndReassembly::CONTINUATION, std::move(segment2)); base_view = GetPacketView(std::move(builder2)); controller.OnPdu(base_view); auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END, std::move(segment3)); base_view = GetPacketView(std::move(builder3)); controller.OnPdu(base_view); sync_handler(queue_handler_); auto payload = channel_queue.GetUpEnd()->TryDequeue(); EXPECT_EQ(payload, nullptr); } TEST_F(ErtmDataControllerTest, transmit_with_fcs) { TEST_F(ErtmDataControllerTest, transmit_with_fcs) { common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10}; testing::MockScheduler scheduler; testing::MockScheduler scheduler; Loading