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

Commit 8c16302d authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2CAP LE COC: Handle credit correctly

Bug: 141558626
Test: bluetooth_test_gd and run_cert.sh
Change-Id: I5daa94d09d9ef7e2d769b7433d05b6310ca0e3e7
parent 516c7777
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -111,6 +111,8 @@ class Link : public l2cap::internal::ILink {
    return GetDevice().ToString();
  }

  void SendLeCredit(Cid local_cid, uint16_t credit) override {}

 private:
  os::Handler* l2cap_handler_;
  l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
+4 −1
Original line number Diff line number Diff line
@@ -28,9 +28,12 @@ namespace internal {
 */
class ILink {
 public:
  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) = 0;
  virtual ~ILink() = default;
  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) = 0;
  virtual hci::AddressWithType GetDevice() = 0;

  // To be used by LE credit based channel data controller over LE link
  virtual void SendLeCredit(Cid local_cid, uint16_t credit) = 0;
};
}  // namespace internal
}  // namespace l2cap
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ class MockILink : public ILink {
 public:
  MOCK_METHOD(hci::AddressWithType, GetDevice, (), (override));
  MOCK_METHOD(void, SendDisconnectionRequest, (Cid, Cid), (override));
  MOCK_METHOD(void, SendLeCredit, (Cid, uint16_t), (override));
};

}  // namespace testing
+28 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "l2cap/internal/le_credit_based_channel_data_controller.h"

#include "l2cap/l2cap_packets.h"
#include "l2cap/le/internal/link.h"
#include "packet/fragmenting_inserter.h"
#include "packet/raw_builder.h"

@@ -27,8 +28,8 @@ namespace internal {
LeCreditBasedDataController::LeCreditBasedDataController(ILink* link, 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) {
}
    : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler),
      link_(link) {}

void LeCreditBasedDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
  auto sdu_size = sdu->size();
@@ -51,7 +52,16 @@ void LeCreditBasedDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilde
    builder = BasicFrameBuilder::Create(remote_cid_, std::move(segments[i]));
    pdu_queue_.emplace(std::move(builder));
  }
  if (credits_ >= segments.size()) {
    scheduler_->OnPacketsReady(cid_, segments.size());
    credits_ -= segments.size();
  } else if (credits_ > 0) {
    scheduler_->OnPacketsReady(cid_, credits_);
    pending_frames_count_ += (segments.size() - credits_);
    credits_ = 0;
  } else {
    pending_frames_count_ += segments.size();
  }
}

void LeCreditBasedDataController::OnPdu(packet::PacketView<true> pdu) {
@@ -85,8 +95,10 @@ void LeCreditBasedDataController::OnPdu(packet::PacketView<true> pdu) {
    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
    link_->SendDisconnectionRequest(cid_, remote_cid_);
  }
  // TODO: Improve the logic by sending credit only after user dequeued the SDU
  link_->SendLeCredit(cid_, 1);
}

std::unique_ptr<packet::BasePacketBuilder> LeCreditBasedDataController::GetNextPacket() {
@@ -105,7 +117,18 @@ void LeCreditBasedDataController::SetMps(uint16_t mps) {

void LeCreditBasedDataController::OnCredit(uint16_t credits) {
  int total_credits = credits_ + credits;
  credits_ = total_credits > 0xffff ? 0xffff : total_credits;
  if (total_credits > 0xffff) {
    link_->SendDisconnectionRequest(cid_, remote_cid_);
  }
  credits_ = total_credits;
  if (pending_frames_count_ > 0 && credits_ >= pending_frames_count_) {
    scheduler_->OnPacketsReady(cid_, pending_frames_count_);
    credits_ -= pending_frames_count_;
  } else if (pending_frames_count_ > 0) {
    scheduler_->OnPacketsReady(cid_, credits_);
    pending_frames_count_ -= credits_;
    credits_ = 0;
  }
}

}  // namespace internal
+2 −0
Original line number Diff line number Diff line
@@ -65,9 +65,11 @@ class LeCreditBasedDataController : public DataController {
  os::Handler* handler_;
  std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_;
  Scheduler* scheduler_;
  ILink* link_;
  Mtu mtu_ = 512;
  uint16_t mps_ = 251;
  uint16_t credits_ = 0;
  uint16_t pending_frames_count_ = 0;

  class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
   public:
Loading