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

Commit 350b8fa9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "L2CAP: Allow opening connection, and add PTS request_connection test"

parents 8b77fac1 78215e9b
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -9,10 +9,13 @@ service L2capModuleCert {
  rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {}
  rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {}
  rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {}
  rpc SetOnIncomingConnectionRequest(SetOnIncomingConnectionRequestRequest)
      returns (SetOnIncomingConnectionRequestResponse) {}
  rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {}
  rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {}
  rpc SendConfigurationRequest(ConfigurationRequest) returns (SendConfigurationRequestResult) {}
  rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {}
  rpc FetchOpenedChannels(FetchOpenedChannelsRequest) returns (FetchOpenedChannelsResponse) {}
}

message L2capPacket {
@@ -25,17 +28,25 @@ message ConnectionCompleteEvent {
  facade.BluetoothAddress remote = 1;
}

message SetOnIncomingConnectionRequestRequest {
  bool accept = 1;
}

message SetOnIncomingConnectionRequestResponse {}

message DisconnectLinkRequest {
  facade.BluetoothAddress remote = 1;
}

message ConnectionRequest {
  facade.BluetoothAddress remote = 1;
  uint32 dcid = 2;
  uint32 psm = 2;
  uint32 scid = 3;
}

message ConfigurationRequest {}
message ConfigurationRequest {
  uint32 scid = 1;
}

message SendConfigurationRequestResult {}

@@ -44,3 +55,9 @@ message DisconnectionRequest {
  uint32 dcid = 2;
  uint32 scid = 3;
}

message FetchOpenedChannelsRequest {}

message FetchOpenedChannelsResponse {
  repeated uint32 cid = 1;
}
 No newline at end of file
+79 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "grpc/grpc_event_stream.h"
#include "hci/acl_manager.h"
#include "hci/cert/cert.h"
#include "hci/hci_packets.h"
#include "l2cap/classic/cert/api.grpc.pb.h"
#include "l2cap/classic/l2cap_classic_module.h"
#include "l2cap/l2cap_packets.h"
@@ -74,6 +75,16 @@ class L2capModuleCertService : public L2capModuleCert::Service {
    return connection_complete_stream_.HandleRequest(context, request, writer);
  }

  ::grpc::Status SetOnIncomingConnectionRequest(
      ::grpc::ServerContext* context,
      const ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestRequest* request,
      ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestResponse* response) override {
    accept_incoming_connection_ = request->accept();
    return ::grpc::Status::OK;
  }

  bool accept_incoming_connection_ = true;

  ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const L2capPacket* request,
                                 ::google::protobuf::Empty* response) override {
    std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
@@ -90,7 +101,7 @@ class L2capModuleCertService : public L2capModuleCert::Service {

  ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request,
                                       ::google::protobuf::Empty* response) override {
    auto builder = ConnectionRequestBuilder::Create(1, 1, 101);
    auto builder = ConnectionRequestBuilder::Create(1, 1, request->scid());
    auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder));
    outgoing_packet_queue_.push(std::move(l2cap_builder));
    if (outgoing_packet_queue_.size() == 1) {
@@ -104,7 +115,7 @@ class L2capModuleCertService : public L2capModuleCert::Service {
  ::grpc::Status SendConfigurationRequest(
      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationRequest* request,
      ::bluetooth::l2cap::classic::cert::SendConfigurationRequestResult* response) override {
    auto builder = ConfigurationRequestBuilder::Create(1, 0x40, Continuation::END, {});
    auto builder = ConfigurationRequestBuilder::Create(1, request->scid(), Continuation::END, {});
    auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder));
    outgoing_packet_queue_.push(std::move(l2cap_builder));
    if (outgoing_packet_queue_.size() == 1) {
@@ -127,6 +138,14 @@ class L2capModuleCertService : public L2capModuleCert::Service {
    return ::grpc::Status::OK;
  }

  ::grpc::Status FetchOpenedChannels(
      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsRequest* request,
      ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsResponse* response) override {
    response->mutable_cid()->Add(open_channels_.begin(), open_channels_.end());
    return ::grpc::Status::OK;
  }
  std::vector<uint16_t> open_channels_;

  std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() {
    auto basic_frame_builder = std::move(outgoing_packet_queue_.front());
    outgoing_packet_queue_.pop();
@@ -159,6 +178,58 @@ class L2capModuleCertService : public L2capModuleCert::Service {
    l2cap_packet.set_payload(data);
    l2cap_packet.set_channel(basic_frame_view.GetChannelId());
    l2cap_stream_.OnIncomingEvent(l2cap_packet);

    if (basic_frame_view.GetChannelId() == kClassicSignallingCid) {
      ControlView control_view = ControlView::Create(basic_frame_view.GetPayload());
      ASSERT(control_view.IsValid());
      handle_signalling_packet(control_view);
    }
  }

  void handle_signalling_packet(ControlView control_view) {
    auto code = control_view.GetCode();
    switch (code) {
      case CommandCode::CONNECTION_REQUEST: {
        ConnectionRequestView view = ConnectionRequestView::Create(control_view);
        ASSERT(view.IsValid());
        open_channels_.push_back(view.GetSourceCid());
        auto builder = ConnectionResponseBuilder::Create(
            view.GetIdentifier(), view.GetSourceCid(), view.GetSourceCid(),
            accept_incoming_connection_ ? ConnectionResponseResult::SUCCESS : ConnectionResponseResult::INVALID_CID,
            ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
        outgoing_packet_queue_.push(std::move(l2cap_builder));
        if (outgoing_packet_queue_.size() == 1) {
          acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
              handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
        }

        break;
      }
      case CommandCode::CONNECTION_RESPONSE: {
        ConnectionResponseView view = ConnectionResponseView::Create(control_view);
        ASSERT(view.IsValid());
        open_channels_.push_back(view.GetSourceCid());
        break;
      }

      case CommandCode::CONFIGURATION_REQUEST: {
        ConfigurationRequestView view = ConfigurationRequestView::Create(control_view);
        ASSERT(view.IsValid());
        auto builder =
            ConfigurationResponseBuilder::Create(view.GetIdentifier(), view.GetDestinationCid(), Continuation::END,
                                                 ConfigurationResponseResult::SUCCESS, {});
        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
        outgoing_packet_queue_.push(std::move(l2cap_builder));
        if (outgoing_packet_queue_.size() == 1) {
          acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
              handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
        }
        break;
      }
      default:
        return;
    }
  }

  std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_;
@@ -177,12 +248,17 @@ class L2capModuleCertService : public L2capModuleCert::Service {
      module_->acl_connection_->RegisterDisconnectCallback(common::BindOnce([](hci::ErrorCode) {}), module_->handler_);
      module_->acl_connection_->GetAclQueueEnd()->RegisterDequeue(
          module_->handler_, common::Bind(&L2capModuleCertService::on_incoming_packet, common::Unretained(module_)));
      dequeue_registered_ = true;
    }
    void OnConnectFail(hci::Address address, hci::ErrorCode reason) override {}

    ~AclCallbacks() {
      if (dequeue_registered_) {
        module_->acl_connection_->GetAclQueueEnd()->UnregisterDequeue();
      }
    }

    bool dequeue_registered_ = false;

    L2capModuleCertService* module_;
  } acl_callbacks{this};
+24 −3
Original line number Diff line number Diff line
@@ -84,12 +84,15 @@ class SimpleL2capTest(GdBaseTestClass):
        )
        dut_connection_stream.unsubscribe()

        self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest())
        self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=0x101))
        time.sleep(1)

        open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest())
        cid = open_channels.cid[0]

        dut_packet_stream.subscribe()
        cert_packet_stream.subscribe()
        self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest())
        self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(scid=cid))

        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"abc"))
        dut_packet_stream.assert_event_occurs(
@@ -100,7 +103,7 @@ class SimpleL2capTest(GdBaseTestClass):
            lambda packet: b"123" in packet.payload
        )

        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=64, payload=b"123"))
        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=cid, payload=b"123"))
        dut_packet_stream.assert_event_occurs(
            lambda packet: b"123" in packet.payload
        )
@@ -114,3 +117,21 @@ class SimpleL2capTest(GdBaseTestClass):
        time.sleep(1)
        dut_packet_stream.unsubscribe()
        cert_packet_stream.unsubscribe()

    def test_basic_operation_request_connection(self):
        """
        L2CAP/COS/CED/BV-01-C [Request Connection]
        Verify that the IUT is able to request the connection establishment for an L2CAP data channel and
        initiate the configuration procedure.
        """
        self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
        cert_connection_stream = self.cert_device.l2cap.connection_complete_stream
        cert_connection_stream.subscribe()
        self.device_under_test.l2cap.Connect(self.cert_address)
        cert_connection_stream.assert_event_occurs(
            lambda device: device.remote == self.dut_address
        )
        cert_connection_stream.unsubscribe()
        self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=0x01))
        time.sleep(1)
+20 −0
Original line number Diff line number Diff line
@@ -95,6 +95,18 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
    return ::grpc::Status::OK;
  }

  ::grpc::Status OpenChannel(::grpc::ServerContext* context,
                             const ::bluetooth::l2cap::classic::OpenChannelRequest* request,
                             ::google::protobuf::Empty* response) override {
    auto psm = request->psm();
    dynamic_channel_helper_map_.emplace(
        psm, std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, psm));
    hci::Address peer;
    ASSERT(hci::Address::FromString(request->remote().address(), peer));
    dynamic_channel_helper_map_[psm]->Connect(peer);
    return ::grpc::Status::OK;
  }

  ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
                                ::grpc::ServerWriter<classic::L2capPacket>* writer) override {
    return l2cap_stream_.HandleRequest(context, request, writer);
@@ -189,6 +201,12 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
          common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_);
    }

    void Connect(hci::Address address) {
      dynamic_channel_manager_->ConnectChannel(
          address, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)),
          common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_);
    }

    void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result,
                                                std::unique_ptr<DynamicChannelService> service) {}

@@ -199,6 +217,8 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service {
      channel_ = std::move(channel);
    }

    void on_connect_fail(DynamicChannelManager::ConnectionResult result) {}

    void on_incoming_packet() {
      auto packet = channel_->GetQueueUpEnd()->TryDequeue();
      std::string data = std::string(packet->begin(), packet->end());
+35 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm
  }
  Cid cid = kFirstDynamicChannel;
  for (; cid <= kLastDynamicChannel; cid++) {
    if (channels_.find(cid) == channels_.end()) break;
    if (used_cid_.find(cid) == used_cid_.end()) break;
  }
  if (cid > kLastDynamicChannel) {
    LOG_WARN("All cid are used");
@@ -51,9 +51,42 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm
             link_->GetDevice().ToString().c_str());
  ASSERT(elem.first->second != nullptr);
  used_remote_cid_.insert(remote_cid);
  used_cid_.insert(cid);
  return elem.first->second;
}

std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateReservedChannel(Cid reserved_cid, Psm psm,
                                                                                     Cid remote_cid,
                                                                                     SecurityPolicy security_policy) {
  ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str());
  ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm);

  if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
    LOG_INFO("Remote cid 0x%x is used", remote_cid);
    return nullptr;
  }
  auto elem = channels_.try_emplace(
      reserved_cid, std::make_shared<DynamicChannelImpl>(psm, reserved_cid, remote_cid, link_, l2cap_handler_));
  ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm,
             link_->GetDevice().ToString().c_str());
  ASSERT(elem.first->second != nullptr);
  used_remote_cid_.insert(remote_cid);
  return elem.first->second;
}

Cid DynamicChannelAllocator::ReserveChannel() {
  Cid cid = kFirstDynamicChannel;
  for (; cid <= kLastDynamicChannel; cid++) {
    if (used_cid_.find(cid) == used_cid_.end()) break;
  }
  if (cid > kLastDynamicChannel) {
    LOG_WARN("All cid are used");
    return kInvalidCid;
  }
  used_cid_.insert(cid);
  return cid;
}

void DynamicChannelAllocator::FreeChannel(Cid cid) {
  auto channel = FindChannelByCid(cid);
  if (channel == nullptr) {
@@ -62,6 +95,7 @@ void DynamicChannelAllocator::FreeChannel(Cid cid) {
  }
  used_remote_cid_.erase(channel->GetRemoteCid());
  channels_.erase(cid);
  used_cid_.erase(cid);
}

bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
Loading