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

Commit 56e17cd4 authored by Hansong Zhang's avatar Hansong Zhang Committed by Gerrit Code Review
Browse files

Merge changes I37defeed,I6fbe6ef8

* changes:
  L2CAP: LE Credit Based Channel Data Controller
  L2CAP Cert: Add support for sending I-Frame and S-Frame
parents cc691a25 687b6e24
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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",
@@ -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",
+26 −0
Original line number Diff line number Diff line
@@ -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) {}
@@ -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;
}
+31 −0
Original line number Diff line number Diff line
@@ -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());
+4 −1
Original line number Diff line number Diff line
@@ -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())
@@ -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))
+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