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

Commit 4db917c0 authored by Hansong Zhang's avatar Hansong Zhang Committed by android-build-merger
Browse files

L2CAP: Add Reassembler to separate outgoing and incoming queue

am: 8e8badfb

Change-Id: Ia28c80a0913d6a7427f140d8a6fb788357a73762
parents 0bdf3ed7 8e8badfb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ filegroup {
        "classic/internal/signalling_manager.cc",
        "classic/l2cap_classic_module.cc",
        "internal/scheduler_fifo.cc",
        "internal/reassembler.cc",
        "le/internal/fixed_channel_impl.cc",
        "le/internal/fixed_channel_service_manager_impl.cc",
        "le/internal/link_manager.cc",
@@ -39,6 +40,7 @@ filegroup {
        "classic/internal/link_manager_test.cc",
        "classic/internal/signalling_manager_test.cc",
        "internal/fixed_channel_allocator_test.cc",
        "internal/reassembler_test.cc",
        "internal/scheduler_fifo_test.cc",
        "l2cap_packet_test.cc",
        "le/internal/fixed_channel_impl_test.cc",
+5 −1
Original line number Diff line number Diff line
@@ -34,7 +34,8 @@ Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_c
           l2cap::internal::ParameterProvider* parameter_provider,
           DynamicChannelServiceManagerImpl* dynamic_service_manager,
           FixedChannelServiceManagerImpl* fixed_service_manager)
    : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)), scheduler_(std::move(scheduler)),
    : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)),
      reassembler_(acl_connection_->GetAclQueueEnd(), l2cap_handler_), scheduler_(std::move(scheduler)),
      parameter_provider_(parameter_provider), dynamic_service_manager_(dynamic_service_manager),
      fixed_service_manager_(fixed_service_manager),
      signalling_manager_(l2cap_handler_, this, dynamic_service_manager_, &dynamic_channel_allocator_,
@@ -59,6 +60,7 @@ void Link::Disconnect() {
std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
  auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
  scheduler_->AttachChannel(cid, channel->GetQueueDownEnd(), cid);
  reassembler_.AttachChannel(cid, channel->GetQueueDownEnd(), {});
  return channel;
}

@@ -87,6 +89,7 @@ std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid re
  auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
  if (channel != nullptr) {
    scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid());
    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), {});
  }
  return channel;
}
@@ -96,6 +99,7 @@ std::shared_ptr<DynamicChannelImpl> Link::AllocateReservedDynamicChannel(Cid res
  auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
  if (channel != nullptr) {
    scheduler_->AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel->GetRemoteCid());
    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), {});
  }
  return channel;
}
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
#include "l2cap/internal/fixed_channel_allocator.h"
#include "l2cap/internal/parameter_provider.h"
#include "l2cap/internal/reassembler.h"
#include "l2cap/internal/scheduler.h"
#include "os/alarm.h"
#include "os/handler.h"
@@ -87,6 +88,7 @@ class Link {
  l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
  DynamicChannelAllocator dynamic_channel_allocator_{this, l2cap_handler_};
  std::unique_ptr<hci::AclConnection> acl_connection_;
  l2cap::internal::Reassembler reassembler_;
  std::unique_ptr<l2cap::internal::Scheduler> scheduler_;
  l2cap::internal::ParameterProvider* parameter_provider_;
  DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+92 −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/reassembler.h"
#include "common/bidi_queue.h"
#include "l2cap/cid.h"
#include "l2cap/l2cap_packets.h"
#include "packet/base_packet_builder.h"
#include "packet/packet_view.h"
#

namespace bluetooth {
namespace l2cap {
namespace internal {
Reassembler::Reassembler(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler)
    : link_queue_up_end_(link_queue_up_end), handler_(handler) {
  ASSERT(link_queue_up_end_ != nullptr && handler_ != nullptr);
  link_queue_up_end_->RegisterDequeue(
      handler_, common::Bind(&Reassembler::link_queue_dequeue_callback, common::Unretained(this)));
}

Reassembler::~Reassembler() {
  link_queue_up_end_->UnregisterDequeue();
}

void Reassembler::AttachChannel(Cid cid, Reassembler::UpperQueueDownEnd* channel_down_end,
                                Reassembler::ChannelConfigurationOptions options) {
  ASSERT_LOG(channel_map_.find(cid) == channel_map_.end(), "Channel is already attached");
  auto pair = ChannelBufferAndOptions(channel_down_end, options);
  channel_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
                       std::forward_as_tuple(channel_down_end, options));
}

void Reassembler::DetachChannel(Cid cid) {
  ASSERT_LOG(channel_map_.find(cid) != channel_map_.end(), "Channel is not attached");
  channel_map_.erase(cid);
}

void Reassembler::link_queue_dequeue_callback() {
  auto packet = link_queue_up_end_->TryDequeue();
  auto basic_frame_view = BasicFrameView::Create(*packet);
  if (!basic_frame_view.IsValid()) {
    LOG_WARN("Received an invalid basic frame");
    return;
  }
  Cid cid = static_cast<Cid>(basic_frame_view.GetChannelId());
  auto channel = channel_map_.find(cid);
  if (channel == channel_map_.end()) {
    LOG_WARN("Received a packet with invalid cid: %d", cid);
    return;  // Channel is not attached to scheduler
  }

  auto channel_mode = channel->second.options_.mode_;
  switch (channel_mode) {
    case RetransmissionAndFlowControlModeOption::L2CAP_BASIC:
      handle_basic_mode_packet(cid, basic_frame_view);
      break;
    case RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION:
      handle_enhanced_retransmission_mode_packet(cid, std::move(basic_frame_view));
      break;
    default:
      LOG_WARN("channel mode is not supported: %d", static_cast<int>(channel_mode));
  }
}

void Reassembler::handle_basic_mode_packet(Cid cid, const BasicFrameView& view) {
  auto channel = channel_map_.find(cid);
  auto& enqueue_buffer = channel->second.enqueue_buffer_;

  enqueue_buffer.Enqueue(std::make_unique<PacketView<kLittleEndian>>(view.GetPayload()), handler_);
}

void Reassembler::handle_enhanced_retransmission_mode_packet(Cid cid, BasicFrameView view) {
  LOG_ERROR("Enhanced retransmission mode is not implemented");
}

}  // namespace internal
}  // namespace l2cap
}  // namespace bluetooth
+90 −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.
 */

#pragma once

#include <unordered_map>
#include <utility>

#include "common/bidi_queue.h"
#include "l2cap/cid.h"
#include "l2cap/l2cap_packets.h"
#include "l2cap/mtu.h"
#include "os/queue.h"
#include "packet/base_packet_builder.h"
#include "packet/packet_view.h"

namespace bluetooth {
namespace l2cap {
namespace internal {

/**
 * Handle the reassembly of L2CAP SDU from PDU.
 * Dequeue incoming packets from LinkQueueUpEnd, and enqueue it to ChannelQueueDownEnd. Note: If a channel
 * cannot dequeue from ChannelQueueDownEnd so that the buffer for incoming packet is full, further incoming packets will
 * be dropped.
 * The Reassembler keeps the reference to ChannelImpl objects, because it needs to check channel mode and parameters.
 */
class Reassembler {
 public:
  using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
  using UpperDequeue = packet::BasePacketBuilder;
  using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
  using LowerEnqueue = UpperDequeue;
  using LowerDequeue = UpperEnqueue;
  using LowerQueueUpEnd = common::BidiQueueEnd<LowerEnqueue, LowerDequeue>;

  Reassembler(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler);
  ~Reassembler();

  struct ChannelConfigurationOptions {
    Mtu incoming_mtu_ = kDefaultClassicMtu;
    RetransmissionAndFlowControlModeOption mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
    // TODO: Add all RetransmissionAndFlowControlConfigurationOptions
    FcsType fcs_type_ = FcsType::NO_FCS;
  };

  /**
   * Attach a channel for packet reassembly.
   * If the channel is reconfigured, signalling manager should detach channel and attach channel again.
   */
  void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, ChannelConfigurationOptions options);

  /**
   * Detach a channel for packet reassembly. Incoming packets won't be delivered to the specified cid.
   */
  void DetachChannel(Cid cid);

 private:
  struct ChannelBufferAndOptions {
    ChannelBufferAndOptions(UpperQueueDownEnd* queue_end, ChannelConfigurationOptions options)
        : enqueue_buffer_(queue_end), options_(std::move(options)) {}
    os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
    ChannelConfigurationOptions options_;
  };

  LowerQueueUpEnd* link_queue_up_end_;
  os::Handler* handler_;
  std::unordered_map<Cid, ChannelBufferAndOptions> channel_map_;

  void link_queue_dequeue_callback();
  void handle_basic_mode_packet(Cid cid, const BasicFrameView& view);
  void handle_enhanced_retransmission_mode_packet(Cid cid, BasicFrameView view);
};

}  // namespace internal
}  // namespace l2cap
}  // namespace bluetooth
Loading