Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afe7cebb authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2CAP ERTM FCS support

Bug: 144730758
Test: bluetooth_test_gd
Change-Id: I57b0c7f6a8c806e26c4f68ee75e8403e5a9090e9
parent 87d879fd
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

#include "l2cap/internal/basic_mode_channel_data_controller.h"

#include "l2cap/l2cap_packets.h"

namespace bluetooth {
namespace l2cap {
namespace internal {
@@ -31,11 +33,15 @@ void BasicModeDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> s
  scheduler_->OnPacketsReady(cid_, 1);
}

void BasicModeDataController::OnPdu(BasicFrameView pdu) {
  enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(pdu.GetPayload()), handler_);
void BasicModeDataController::OnPdu(packet::PacketView<true> pdu) {
  auto basic_frame_view = BasicFrameView::Create(pdu);
  if (!basic_frame_view.IsValid()) {
    return;
  }
  enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(basic_frame_view.GetPayload()), handler_);
}

std::unique_ptr<BasicFrameBuilder> BasicModeDataController::GetNextPacket() {
std::unique_ptr<packet::BasePacketBuilder> BasicModeDataController::GetNextPacket() {
  auto next = std::move(pdu_queue_.front());
  pdu_queue_.pop();
  return next;
+3 −3
Original line number Diff line number Diff line
@@ -46,9 +46,9 @@ class BasicModeDataController : public DataController {

  void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;

  void OnPdu(BasicFrameView pdu) override;
  void OnPdu(packet::PacketView<true> pdu) override;

  std::unique_ptr<BasicFrameBuilder> GetNextPacket() override;
  std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() override;

  void EnableFcs(bool enabled) override {}
  void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {}
@@ -58,7 +58,7 @@ class BasicModeDataController : public DataController {
  Cid remote_cid_;
  os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
  os::Handler* handler_;
  std::queue<std::unique_ptr<BasicFrameBuilder>> pdu_queue_;
  std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_;
  Scheduler* scheduler_;
};

+11 −5
Original line number Diff line number Diff line
@@ -74,22 +74,28 @@ TEST_F(BasicModeDataControllerTest, transmit) {
  testing::MockScheduler scheduler;
  BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
  EXPECT_CALL(scheduler, OnPacketsReady(1, 1));
  controller.OnSdu(CreateSdu({1, 2, 3}));
  controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
  auto next_packet = controller.GetNextPacket();
  EXPECT_NE(next_packet, nullptr);
  auto view = GetPacketView(std::move(next_packet));
  auto pdu_view = BasicFrameView::Create(view);
  EXPECT_TRUE(pdu_view.IsValid());
  auto payload = pdu_view.GetPayload();
  std::string data = std::string(payload.begin(), payload.end());
  EXPECT_EQ(data, "abcd");
}

TEST_F(BasicModeDataControllerTest, receive) {
  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
  testing::MockScheduler scheduler;
  BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
  auto base_view = GetPacketView(CreateSdu({0, 0, 1, 0}));
  auto basic_frame_view = BasicFrameView::Create(base_view);
  EXPECT_TRUE(basic_frame_view.IsValid());
  controller.OnPdu(basic_frame_view);
  auto base_view = GetPacketView(BasicFrameBuilder::Create(1, CreateSdu({'a', 'b', 'c', 'd'})));
  controller.OnPdu(base_view);
  sync_handler(queue_handler_);
  auto packet_view = channel_queue.GetUpEnd()->TryDequeue();
  EXPECT_NE(packet_view, nullptr);
  std::string data = std::string(packet_view->begin(), packet_view->end());
  EXPECT_EQ(data, "abcd");
}

}  // namespace
+2 −2
Original line number Diff line number Diff line
@@ -34,10 +34,10 @@ class DataController {
  virtual void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) = 0;

  // PDUs -> SDU and enqueue to channel queue end
  virtual void OnPdu(BasicFrameView pdu) = 0;
  virtual void OnPdu(packet::PacketView<true> pdu) = 0;

  // Used by Scheduler to get next PDU
  virtual std::unique_ptr<BasicFrameBuilder> GetNextPacket() = 0;
  virtual std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() = 0;

  // Set FCS mode. This only applies to some modes (ERTM).
  virtual void EnableFcs(bool enabled) = 0;
+85 −16
Original line number Diff line number Diff line
@@ -555,14 +555,24 @@ struct ErtmController::impl {

  void _send_i_frame(SegmentationAndReassembly sar, std::unique_ptr<CopyablePacketBuilder> segment, uint8_t req_seq,
                     uint8_t tx_seq, uint16_t sdu_size = 0, Final f = Final::NOT_SET) {
    std::unique_ptr<EnhancedInformationFrameBuilder> builder;
    std::unique_ptr<packet::BasePacketBuilder> builder;
    if (sar == SegmentationAndReassembly::START) {
      if (controller_->fcs_enabled_) {
        builder = EnhancedInformationStartFrameWithFcsBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq,
                                                                      sdu_size, std::move(segment));
      } else {
        builder = EnhancedInformationStartFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sdu_size,
                                                               std::move(segment));
      }
    } else {
      if (controller_->fcs_enabled_) {
        builder = EnhancedInformationFrameWithFcsBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sar,
                                                                 std::move(segment));
      } else {
        builder = EnhancedInformationFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sar,
                                                          std::move(segment));
      }
    }
    controller_->send_pdu(std::move(builder));
  }

@@ -575,7 +585,6 @@ struct ErtmController::impl {
    std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
        std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(next_tx_seq_)->second));
    _send_i_frame(sar, std::move(copyable_packet_builder), buffer_seq_, next_tx_seq_, sdu_size, f);
    // TODO hsz fix me
    unacked_frames_++;
    frames_sent_++;
    retry_i_frames_[next_tx_seq_] = 1;
@@ -599,7 +608,12 @@ struct ErtmController::impl {
  }

  void _send_s_frame(SupervisoryFunction s, uint8_t req_seq, Poll p, Final f) {
    auto builder = EnhancedSupervisoryFrameBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
    std::unique_ptr<packet::BasePacketBuilder> builder;
    if (controller_->fcs_enabled_) {
      builder = EnhancedSupervisoryFrameWithFcsBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
    } else {
      builder = EnhancedSupervisoryFrameBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
    }
    controller_->send_pdu(std::move(builder));
  }

@@ -770,13 +784,9 @@ struct ErtmController::impl {

// Segmentation is handled here
void ErtmController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
  // TODO: Optimize the calculation. We don't need to count for SDU length in CONTINUATION or END packets. We don't need
  // to FCS when disabled.
  size_t size_each_packet =
      (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */);
  auto sdu_size = sdu->size();
  std::vector<std::unique_ptr<packet::RawBuilder>> segments;
  packet::FragmentingInserter fragmenting_inserter(size_each_packet, std::back_insert_iterator(segments));
  packet::FragmentingInserter fragmenting_inserter(size_each_packet_, std::back_insert_iterator(segments));
  sdu->Serialize(fragmenting_inserter);
  fragmenting_inserter.finalize();
  if (segments.size() == 1) {
@@ -790,8 +800,20 @@ void ErtmController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
  pimpl_->data_request(SegmentationAndReassembly::END, std::move(segments.back()));
}

void ErtmController::OnPdu(BasicFrameView pdu) {
  auto standard_frame_view = StandardFrameView::Create(pdu);
void ErtmController::OnPdu(packet::PacketView<true> pdu) {
  if (fcs_enabled_) {
    on_pdu_fcs(pdu);
  } else {
    on_pdu_no_fcs(pdu);
  }
}

void ErtmController::on_pdu_no_fcs(const packet::PacketView<true>& pdu) {
  auto basic_frame_view = BasicFrameView::Create(pdu);
  if (!basic_frame_view.IsValid()) {
    return;
  }
  auto standard_frame_view = StandardFrameView::Create(basic_frame_view);
  if (!standard_frame_view.IsValid()) {
    LOG_WARN("Received invalid frame");
    return;
@@ -833,7 +855,54 @@ void ErtmController::OnPdu(BasicFrameView pdu) {
  }
}

std::unique_ptr<BasicFrameBuilder> ErtmController::GetNextPacket() {
void ErtmController::on_pdu_fcs(const packet::PacketView<true>& pdu) {
  auto basic_frame_view = BasicFrameWithFcsView::Create(pdu);
  if (!basic_frame_view.IsValid()) {
    return;
  }
  auto standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
  if (!standard_frame_view.IsValid()) {
    LOG_WARN("Received invalid frame");
    return;
  }
  auto type = standard_frame_view.GetFrameType();
  if (type == FrameType::I_FRAME) {
    auto i_frame_view = EnhancedInformationFrameWithFcsView::Create(standard_frame_view);
    if (!i_frame_view.IsValid()) {
      LOG_WARN("Received invalid frame");
      return;
    }
    pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(),
                         i_frame_view.GetPayload());
  } else if (type == FrameType::S_FRAME) {
    auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view);
    if (!s_frame_view.IsValid()) {
      LOG_WARN("Received invalid frame");
      return;
    }
    auto req_seq = s_frame_view.GetReqSeq();
    auto f = s_frame_view.GetF();
    auto p = s_frame_view.GetP();
    switch (s_frame_view.GetS()) {
      case SupervisoryFunction::RECEIVER_READY:
        pimpl_->recv_rr(req_seq, p, f);
        break;
      case SupervisoryFunction::RECEIVER_NOT_READY:
        pimpl_->recv_rnr(req_seq, p, f);
        break;
      case SupervisoryFunction::REJECT:
        pimpl_->recv_rej(req_seq, p, f);
        break;
      case SupervisoryFunction::SELECT_REJECT:
        pimpl_->recv_srej(req_seq, p, f);
        break;
    }
  } else {
    LOG_WARN("Received invalid frame");
  }
}

std::unique_ptr<packet::BasePacketBuilder> ErtmController::GetNextPacket() {
  auto next = std::move(pdu_queue_.front());
  pdu_queue_.pop();
  return next;
@@ -879,7 +948,7 @@ void ErtmController::EnableFcs(bool enabled) {
  fcs_enabled_ = enabled;
}

void ErtmController::send_pdu(std::unique_ptr<BasicFrameBuilder> pdu) {
void ErtmController::send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu) {
  pdu_queue_.emplace(std::move(pdu));
  scheduler_->OnPacketsReady(cid_, 1);
}
Loading