Merge "Gd shim updates"
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 43befc2..4942eea 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -42,6 +42,7 @@
 #include "btm_api.h"
 #include "btm_int.h"
 #include "btu.h"
+#include "device/include/interop.h"
 #include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
 #include "l2c_api.h"
 #include "osi/include/log.h"
@@ -50,7 +51,6 @@
 #include "stack/gatt/connection_manager.h"
 #include "stack/include/gatt_api.h"
 #include "utl.h"
-#include "device/include/interop.h"
 
 #if (GAP_INCLUDED == TRUE)
 #include "gap_api.h"
@@ -1357,8 +1357,10 @@
     do {
       p_sdp_rec = NULL;
       if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) {
-        p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
-                                            bta_dm_search_cb.uuid, p_sdp_rec);
+        if (!bta_dm_search_cb.uuid.IsEmpty()) {
+          p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
+                                              bta_dm_search_cb.uuid, p_sdp_rec);
+        }
 
         if (p_sdp_rec && SDP_FindProtocolListElemInRec(
                              p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
@@ -1772,7 +1774,6 @@
  *
  ******************************************************************************/
 static void bta_dm_find_services(const RawAddress& bd_addr) {
-
   while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
     Uuid uuid = Uuid::kEmpty;
     if (bta_dm_search_cb.services_to_search &
@@ -1951,7 +1952,8 @@
         BT_DEVICE_TYPE_BLE) &&
        (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) ||
       (transport == BT_TRANSPORT_LE &&
-       interop_match_addr(INTEROP_DISABLE_NAME_REQUEST, &bta_dm_search_cb.peer_bdaddr))) {
+       interop_match_addr(INTEROP_DISABLE_NAME_REQUEST,
+                          &bta_dm_search_cb.peer_bdaddr))) {
     /* Do not perform RNR for LE devices at inquiry complete*/
     bta_dm_search_cb.name_discover_done = true;
   }
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index c6a8a63..a450c27 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -1117,7 +1117,6 @@
 
       LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);
       bt_property_t prop;
-      RawAddress bd_addr;
       Uuid uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
 
       prop.type = BT_PROPERTY_UUIDS;
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 3db2ee9..d8ea94c 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -3152,11 +3152,10 @@
           break;
         } else {
           uint8_t* p_data = p_rsp->param.track;
-          /* Update the UID for current track
-           * Attributes will be fetched after the AVRCP procedure
-           */
           BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
           get_play_status_cmd(p_dev);
+          get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list,
+                                    p_dev);
         }
         break;
 
diff --git a/gd/hci/acl_manager.cc b/gd/hci/acl_manager.cc
index 0e1ad45..2852b6c 100644
--- a/gd/hci/acl_manager.cc
+++ b/gd/hci/acl_manager.cc
@@ -56,7 +56,7 @@
 };
 
 struct AclManager::impl {
-  impl(AclManager& acl_manager) : acl_manager_(acl_manager) {}
+  impl(const AclManager& acl_manager) : acl_manager_(acl_manager) {}
 
   void Start() {
     hci_layer_ = acl_manager_.GetDependency<HciLayer>();
@@ -1580,7 +1580,7 @@
     handler_->Post(BindOnce(&impl::cleanup, common::Unretained(this), handle));
   }
 
-  AclManager& acl_manager_;
+  const AclManager& acl_manager_;
 
   Controller* controller_ = nullptr;
   uint16_t max_acl_packet_credits_ = 0;
diff --git a/gd/hci/acl_manager.h b/gd/hci/acl_manager.h
index 9a0b279..27c4fb3 100644
--- a/gd/hci/acl_manager.h
+++ b/gd/hci/acl_manager.h
@@ -150,11 +150,11 @@
 
  private:
   friend AclManager;
-  AclConnection(AclManager* manager, uint16_t handle, Address address)
+  AclConnection(const AclManager* manager, uint16_t handle, Address address)
       : manager_(manager), handle_(handle), address_(address) {}
-  AclConnection(AclManager* manager, uint16_t handle, Address address, AddressType address_type, Role role)
+  AclConnection(const AclManager* manager, uint16_t handle, Address address, AddressType address_type, Role role)
       : manager_(manager), handle_(handle), address_(address), address_type_(address_type), role_(role) {}
-  AclManager* manager_;
+  const AclManager* manager_;
   uint16_t handle_;
   Address address_;
   AddressType address_type_;
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
index 0d9ee6d..00d1c9d 100644
--- a/gd/hci/hci_packets.pdl
+++ b/gd/hci/hci_packets.pdl
@@ -683,6 +683,8 @@
   UNSPECIFIED_ERROR = 0x1F,
   UNSUPPORTED_LMP_OR_LL_PARAMETER = 0x20,
   ROLE_CHANGE_NOT_ALLOWED = 0x21,
+  ENCRYPTION_MODE_NOT_ACCEPTABLE = 0x25,
+  CONTROLLER_BUSY = 0x3A,
 }
 
 // Events that are defined with their respective commands
@@ -1051,7 +1053,7 @@
   numeric_value : 32, // 000000-999999 decimal or 0x0-0xF423F
 }
 
-packet UserPasskeyReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_REPLY) {
+packet UserPasskeyRequestReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_REPLY) {
   status : ErrorCode,
   bd_addr : Address,
 }
@@ -1413,7 +1415,7 @@
 
 packet DeleteStoredLinkKeyComplete : CommandComplete (command_op_code = DELETE_STORED_LINK_KEY) {
   status : ErrorCode,
-  num_keys_deleted : 8,
+  num_keys_deleted : 16,
 }
 
 packet WriteLocalName : CommandPacket (op_code = WRITE_LOCAL_NAME) {
@@ -2022,6 +2024,13 @@
 packet ReadLocalSupportedCodecs : CommandPacket (op_code = READ_LOCAL_SUPPORTED_CODECS) {
 }
 
+packet ReadLocalSupportedCodecsComplete : CommandComplete (command_op_code = READ_LOCAL_SUPPORTED_CODECS) {
+  status : ErrorCode,
+  _size_(supported_codecs) : 8,
+  supported_codecs : 8[],
+  _size_(vendor_specific_codecs) : 8,
+  vendor_specific_codecs : 32[],
+}
 
   // STATUS_PARAMETERS
 packet ReadFailedContactCounter : ConnectionManagementCommand (op_code = READ_FAILED_CONTACT_COUNTER) {
@@ -2115,6 +2124,12 @@
   _reserved_ : 4,
 }
 
+packet ReadEncryptionKeySizeComplete : CommandComplete (command_op_code = READ_ENCRYPTION_KEY_SIZE) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  key_size : 8,
+}
 
   // TESTING
 enum LoopbackMode : 8 {
@@ -2974,8 +2989,8 @@
   connection_handle : 12,
   _reserved_ : 4,
   version : 8,
-  manufacturer_name : 8,
-  sub_version : 8,
+  manufacturer_name : 16,
+  sub_version : 16,
 }
 
 packet QosSetupComplete : EventPacket (event_code = QOS_SETUP_COMPLETE){
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
index b9d5f6c..fcd6604 100644
--- a/gd/l2cap/Android.bp
+++ b/gd/l2cap/Android.bp
@@ -17,8 +17,9 @@
         "classic/internal/link_manager.cc",
         "classic/internal/signalling_manager.cc",
         "classic/l2cap_classic_module.cc",
-        "internal/scheduler_fifo.cc",
         "internal/reassembler.cc",
+        "internal/scheduler_fifo.cc",
+        "internal/segmenter.cc",
         "le/internal/fixed_channel_impl.cc",
         "le/internal/fixed_channel_service_manager_impl.cc",
         "le/internal/link_manager.cc",
@@ -42,6 +43,7 @@
         "internal/fixed_channel_allocator_test.cc",
         "internal/reassembler_test.cc",
         "internal/scheduler_fifo_test.cc",
+        "internal/segmenter_test.cc",
         "l2cap_packet_test.cc",
         "le/internal/fixed_channel_impl_test.cc",
         "le/internal/fixed_channel_service_manager_test.cc",
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
index d81096d..3eaa42c 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.cc
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
@@ -81,14 +81,46 @@
   return ss.str();
 }
 
+DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetOutgoingConfigurationStatus() const {
+  return outgoing_configuration_status_;
+}
+
 void DynamicChannelImpl::SetOutgoingConfigurationStatus(ConfigurationStatus status) {
   outgoing_configuration_status_ = status;
 }
 
+DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetIncomingConfigurationStatus() const {
+  return incoming_configuration_status_;
+}
+
 void DynamicChannelImpl::SetIncomingConfigurationStatus(ConfigurationStatus status) {
   incoming_configuration_status_ = status;
 }
 
+Mtu DynamicChannelImpl::GetIncomingMtu() const {
+  return incoming_mtu_;
+}
+
+void DynamicChannelImpl::SetIncomingMtu(Mtu mtu) {
+  incoming_mtu_ = mtu;
+}
+
+RetransmissionAndFlowControlModeOption DynamicChannelImpl::GetMode() const {
+  return mode_;
+}
+
+void DynamicChannelImpl::SetMode(RetransmissionAndFlowControlModeOption mode) {
+  mode_ = mode;
+}
+
+FcsType DynamicChannelImpl::GetFcsType() const {
+  return fcs_type_;
+}
+
+void DynamicChannelImpl::SetFcsType(FcsType fcs_type) {
+  fcs_type_ = fcs_type;
+}
+
 }  // namespace internal
 }  // namespace classic
 }  // namespace l2cap
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h
index 905be4f..d7e64f4 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.h
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h
@@ -20,6 +20,8 @@
 #include "hci/address.h"
 #include "l2cap/cid.h"
 #include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
 #include "l2cap/psm.h"
 #include "os/handler.h"
 #include "os/log.h"
@@ -67,16 +69,20 @@
 
   enum class ConfigurationStatus { NOT_CONFIGURED, CONFIGURED };
 
+  virtual ConfigurationStatus GetOutgoingConfigurationStatus() const;
   virtual void SetOutgoingConfigurationStatus(ConfigurationStatus status);
+
+  virtual ConfigurationStatus GetIncomingConfigurationStatus() const;
   virtual void SetIncomingConfigurationStatus(ConfigurationStatus status);
 
-  virtual ConfigurationStatus GetOutgoingConfigurationStatus() const {
-    return outgoing_configuration_status_;
-  }
+  virtual Mtu GetIncomingMtu() const;
+  virtual void SetIncomingMtu(Mtu mtu);
 
-  virtual ConfigurationStatus GetIncomingConfigurationStatus() const {
-    return incoming_configuration_status_;
-  }
+  virtual RetransmissionAndFlowControlModeOption GetMode() const;
+  virtual void SetMode(RetransmissionAndFlowControlModeOption mode);
+
+  virtual FcsType GetFcsType() const;
+  virtual void SetFcsType(FcsType fcs_type);
 
   // TODO(cmanton) Do something a little bit better than this
   bool local_initiated_{false};
@@ -102,6 +108,11 @@
   ConfigurationStatus outgoing_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
   ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
 
+  Mtu incoming_mtu_ = kDefaultClassicMtu;
+  RetransmissionAndFlowControlModeOption mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+  // TODO: Add all RetransmissionAndFlowControlConfigurationOptions
+  FcsType fcs_type_ = FcsType::DEFAULT;
+
   DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl);
 };
 
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index 35da0a2..0577784 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -61,7 +61,7 @@
 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(), {});
+  reassembler_.AttachChannel(cid, channel->GetQueueDownEnd(), nullptr);
   return channel;
 }
 
@@ -96,7 +96,7 @@
   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(), {});
+    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel);
   }
   channel->local_initiated_ = false;
   return channel;
@@ -107,7 +107,7 @@
   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(), {});
+    reassembler_.AttachChannel(channel->GetCid(), channel->GetQueueDownEnd(), channel);
   }
   channel->local_initiated_ = true;
   return channel;
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index fdb1d53..bf2c8cd 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -183,12 +183,42 @@
 }
 
 void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
-                                                      std::vector<std::unique_ptr<ConfigurationOption>> option) {
+                                                      std::vector<std::unique_ptr<ConfigurationOption>> options) {
   auto channel = channel_allocator_->FindChannelByCid(cid);
   if (channel == nullptr) {
     LOG_WARN("Configuration request for an unknown channel");
     return;
   }
+
+  for (auto& option : options) {
+    switch (option->type_) {
+      case ConfigurationOptionType::MTU: {
+        channel->SetIncomingMtu(MtuConfigurationOption::Specialize(option.get())->mtu_);
+        break;
+      }
+      case ConfigurationOptionType::FLUSH_TIMEOUT: {
+        // TODO: Handle this configuration option
+        break;
+      }
+      case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
+        auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
+        channel->SetMode(config->mode_);
+        break;
+      }
+      case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
+        channel->SetFcsType(FrameCheckSequenceOption::Specialize(option.get())->fcs_type_);
+        break;
+      }
+      default:
+        LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
+        auto response =
+            ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
+                                                 ConfigurationResponseResult::UNKNOWN_OPTIONS, {});
+        enqueue_buffer_->Enqueue(std::move(response), handler_);
+        return;
+    }
+  }
+
   auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
                                                        ConfigurationResponseResult::SUCCESS, {});
   enqueue_buffer_->Enqueue(std::move(response), handler_);
diff --git a/gd/l2cap/internal/reassembler.cc b/gd/l2cap/internal/reassembler.cc
index 9e0a9cc..70f2be6 100644
--- a/gd/l2cap/internal/reassembler.cc
+++ b/gd/l2cap/internal/reassembler.cc
@@ -15,12 +15,12 @@
  */
 
 #include "l2cap/internal/reassembler.h"
+
 #include "common/bidi_queue.h"
 #include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/l2cap_packets.h"
-#include "packet/base_packet_builder.h"
 #include "packet/packet_view.h"
-#
 
 namespace bluetooth {
 namespace l2cap {
@@ -37,11 +37,10 @@
 }
 
 void Reassembler::AttachChannel(Cid cid, Reassembler::UpperQueueDownEnd* channel_down_end,
-                                Reassembler::ChannelConfigurationOptions options) {
+                                std::shared_ptr<classic::internal::DynamicChannelImpl> channel) {
   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));
+                       std::forward_as_tuple(channel_down_end, channel));
 }
 
 void Reassembler::DetachChannel(Cid cid) {
@@ -58,12 +57,13 @@
   }
   Cid cid = static_cast<Cid>(basic_frame_view.GetChannelId());
   auto channel = channel_map_.find(cid);
-  if (channel == channel_map_.end()) {
+  if (channel == channel_map_.end() || (cid >= kFirstDynamicChannel && channel->second.channel_ == nullptr)) {
     LOG_WARN("Received a packet with invalid cid: %d", cid);
     return;  // Channel is not attached to scheduler
   }
 
-  auto channel_mode = channel->second.options_.mode_;
+  auto channel_mode = cid < kFirstDynamicChannel ? RetransmissionAndFlowControlModeOption::L2CAP_BASIC
+                                                 : channel->second.channel_->GetMode();
   switch (channel_mode) {
     case RetransmissionAndFlowControlModeOption::L2CAP_BASIC:
       handle_basic_mode_packet(cid, basic_frame_view);
diff --git a/gd/l2cap/internal/reassembler.h b/gd/l2cap/internal/reassembler.h
index 4eb6f70..a1cf903 100644
--- a/gd/l2cap/internal/reassembler.h
+++ b/gd/l2cap/internal/reassembler.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <memory>
 #include <unordered_map>
 #include <utility>
 
@@ -29,6 +30,13 @@
 
 namespace bluetooth {
 namespace l2cap {
+
+namespace classic {
+namespace internal {
+class DynamicChannelImpl;
+}
+}  // namespace classic
+
 namespace internal {
 
 /**
@@ -50,18 +58,14 @@
   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.
+   * If the channel is a dynamic channel, a shared_ptr reference to DynamicChannelImpl is needed to read necessary
+   * config. If the channel is a fixed channel, use nullptr.
+   * TODO (b/144503952): Rethink about channel abstraction
    */
-  void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, ChannelConfigurationOptions options);
+  void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end,
+                     std::shared_ptr<classic::internal::DynamicChannelImpl> channel);
 
   /**
    * Detach a channel for packet reassembly. Incoming packets won't be delivered to the specified cid.
@@ -69,16 +73,16 @@
   void DetachChannel(Cid cid);
 
  private:
-  struct ChannelBufferAndOptions {
-    ChannelBufferAndOptions(UpperQueueDownEnd* queue_end, ChannelConfigurationOptions options)
-        : enqueue_buffer_(queue_end), options_(std::move(options)) {}
+  struct ChannelBuffer {
+    ChannelBuffer(UpperQueueDownEnd* queue_end, std::shared_ptr<classic::internal::DynamicChannelImpl> channel)
+        : enqueue_buffer_(queue_end), channel_(std::move(channel)) {}
     os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
-    ChannelConfigurationOptions options_;
+    std::shared_ptr<classic::internal::DynamicChannelImpl> channel_;
   };
 
   LowerQueueUpEnd* link_queue_up_end_;
   os::Handler* handler_;
-  std::unordered_map<Cid, ChannelBufferAndOptions> channel_map_;
+  std::unordered_map<Cid, ChannelBuffer> channel_map_;
 
   void link_queue_dequeue_callback();
   void handle_basic_mode_packet(Cid cid, const BasicFrameView& view);
diff --git a/gd/l2cap/internal/reassembler_test.cc b/gd/l2cap/internal/reassembler_test.cc
index a1352e7..b3f5d9a 100644
--- a/gd/l2cap/internal/reassembler_test.cc
+++ b/gd/l2cap/internal/reassembler_test.cc
@@ -76,11 +76,11 @@
   Reassembler* reassembler_ = nullptr;
 };
 
-TEST_F(L2capClassicReassemblerTest, receive_basic_mode_packet) {
+TEST_F(L2capClassicReassemblerTest, receive_basic_mode_packet_for_fixed_channel) {
   common::BidiQueue<Reassembler::UpperEnqueue, Reassembler::UpperDequeue> channel_one_queue_{10};
   common::BidiQueue<Reassembler::UpperEnqueue, Reassembler::UpperDequeue> channel_two_queue_{10};
-  reassembler_->AttachChannel(1, channel_one_queue_.GetDownEnd(), {});
-  reassembler_->AttachChannel(2, channel_two_queue_.GetDownEnd(), {});
+  reassembler_->AttachChannel(1, channel_one_queue_.GetDownEnd(), nullptr);
+  reassembler_->AttachChannel(2, channel_two_queue_.GetDownEnd(), nullptr);
   os::EnqueueBuffer<Reassembler::UpperEnqueue> link_queue_enqueue_buffer{link_queue_.GetDownEnd()};
   auto packet_one = CreateSampleL2capPacket(1, {1, 2, 3});
   auto packet_two = CreateSampleL2capPacket(2, {4, 5, 6, 7});
diff --git a/gd/l2cap/internal/scheduler.h b/gd/l2cap/internal/scheduler.h
index 32d00cf..ba4f384 100644
--- a/gd/l2cap/internal/scheduler.h
+++ b/gd/l2cap/internal/scheduler.h
@@ -29,9 +29,10 @@
 /**
  * Handle the scheduling of packets through the l2cap stack.
  * For each attached channel, dequeue its outgoing packets and enqueue it to the given LinkQueueUpEnd, according to some
- * policy (cid). 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.
+ * policy (cid).
+ *
+ * Note: If a channel cannot dequeue from ChannelQueueDownEnd so that the buffer for incoming packet is full, further
+ * incoming packets will be dropped.
  */
 class Scheduler {
  public:
@@ -41,7 +42,6 @@
   using LowerEnqueue = UpperDequeue;
   using LowerDequeue = UpperEnqueue;
   using LowerQueueUpEnd = common::BidiQueueEnd<LowerEnqueue, LowerDequeue>;
-  using DemuxPolicy = common::Callback<Cid(const UpperEnqueue&)>;
 
   /**
    * Attach the channel with the specified ChannelQueueDownEnd into the scheduler.
@@ -60,9 +60,9 @@
   virtual void DetachChannel(Cid cid) {}
 
   /**
-   * Return the lower queue up end, which can be used to enqueue or dequeue.
+   * Callback from the segmenter to indicate that the scheduler could dequeue number_packets from it
    */
-  virtual LowerQueueUpEnd* GetLowerQueueUpEnd() const = 0;
+  virtual void NotifyPacketsReady(Cid cid, int number_packets) {}
 
   virtual ~Scheduler() = default;
 };
diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc
index e2f36ee..cc9cca7 100644
--- a/gd/l2cap/internal/scheduler_fifo.cc
+++ b/gd/l2cap/internal/scheduler_fifo.cc
@@ -22,40 +22,50 @@
 namespace l2cap {
 namespace internal {
 
+Fifo::Fifo(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);
+}
+
 Fifo::~Fifo() {
-  channel_queue_end_map_.clear();
+  segmenter_map_.clear();
   if (link_queue_enqueue_registered_) {
     link_queue_up_end_->UnregisterEnqueue();
   }
 }
 
 void Fifo::AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) {
-  ASSERT(channel_queue_end_map_.find(cid) == channel_queue_end_map_.end());
-  channel_queue_end_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
-                                 std::forward_as_tuple(handler_, channel_down_end, this, cid, remote_cid));
+  ASSERT(segmenter_map_.find(cid) == segmenter_map_.end());
+  segmenter_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
+                         std::forward_as_tuple(handler_, channel_down_end, this, cid, remote_cid));
 }
 
 void Fifo::DetachChannel(Cid cid) {
-  ASSERT(channel_queue_end_map_.find(cid) != channel_queue_end_map_.end());
-  channel_queue_end_map_.erase(cid);
+  ASSERT(segmenter_map_.find(cid) != segmenter_map_.end());
+  segmenter_map_.erase(cid);
+}
+
+void Fifo::NotifyPacketsReady(Cid cid, int number_packets) {
+  next_to_dequeue_and_num_packets.push(std::make_pair(cid, number_packets));
+  try_register_link_queue_enqueue();
 }
 
 std::unique_ptr<Fifo::UpperDequeue> Fifo::link_queue_enqueue_callback() {
-  ASSERT(!next_to_dequeue_.empty());
-  auto channel_id = next_to_dequeue_.front();
-  next_to_dequeue_.pop();
-  auto& dequeue_buffer = channel_queue_end_map_.find(channel_id)->second.dequeue_buffer_;
-  auto packet = std::move(dequeue_buffer.front());
-  dequeue_buffer.pop();
-  if (dequeue_buffer.size() < ChannelQueueEndAndBuffer::kBufferSize) {
-    channel_queue_end_map_.find(channel_id)->second.try_register_dequeue();
+  ASSERT(!next_to_dequeue_and_num_packets.empty());
+  auto& channel_id_and_number_packets = next_to_dequeue_and_num_packets.front();
+  auto channel_id = channel_id_and_number_packets.first;
+  channel_id_and_number_packets.second--;
+  if (channel_id_and_number_packets.second == 0) {
+    next_to_dequeue_and_num_packets.pop();
   }
-  if (next_to_dequeue_.empty()) {
+  auto packet = segmenter_map_.find(channel_id)->second.GetNextPacket();
+
+  segmenter_map_.find(channel_id)->second.NotifyPacketSent();
+  if (next_to_dequeue_and_num_packets.empty()) {
     link_queue_up_end_->UnregisterEnqueue();
     link_queue_enqueue_registered_ = false;
   }
-  Cid remote_channel_id = channel_queue_end_map_.find(channel_id)->second.remote_channel_id_;
-  return BasicFrameBuilder::Create(remote_channel_id, std::move(packet));
+  return packet;
 }
 
 void Fifo::try_register_link_queue_enqueue() {
@@ -67,33 +77,6 @@
   link_queue_enqueue_registered_ = true;
 }
 
-void Fifo::ChannelQueueEndAndBuffer::try_register_dequeue() {
-  if (is_dequeue_registered_) {
-    return;
-  }
-  queue_end_->RegisterDequeue(
-      handler_, common::Bind(&Fifo::ChannelQueueEndAndBuffer::dequeue_callback, common::Unretained(this)));
-  is_dequeue_registered_ = true;
-}
-
-void Fifo::ChannelQueueEndAndBuffer::dequeue_callback() {
-  auto packet = queue_end_->TryDequeue();
-  ASSERT(packet != nullptr);
-  dequeue_buffer_.emplace(std::move(packet));
-  if (dequeue_buffer_.size() >= kBufferSize) {
-    queue_end_->UnregisterDequeue();
-    is_dequeue_registered_ = false;
-  }
-  scheduler_->next_to_dequeue_.push(channel_id_);
-  scheduler_->try_register_link_queue_enqueue();
-}
-
-Fifo::ChannelQueueEndAndBuffer::~ChannelQueueEndAndBuffer() {
-  if (is_dequeue_registered_) {
-    queue_end_->UnregisterDequeue();
-  }
-}
-
 }  // namespace internal
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.h b/gd/l2cap/internal/scheduler_fifo.h
index b394426..b5264b6 100644
--- a/gd/l2cap/internal/scheduler_fifo.h
+++ b/gd/l2cap/internal/scheduler_fifo.h
@@ -23,10 +23,9 @@
 #include "common/bind.h"
 #include "l2cap/cid.h"
 #include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/segmenter.h"
 #include "os/handler.h"
 #include "os/queue.h"
-#include "packet/base_packet_builder.h"
-#include "packet/packet_view.h"
 
 namespace bluetooth {
 namespace l2cap {
@@ -34,45 +33,17 @@
 
 class Fifo : public Scheduler {
  public:
-  Fifo(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);
-  }
-
+  Fifo(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler);
   ~Fifo() override;
   void AttachChannel(Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid) override;
   void DetachChannel(Cid cid) override;
-  LowerQueueUpEnd* GetLowerQueueUpEnd() const override {
-    return link_queue_up_end_;
-  }
+  void NotifyPacketsReady(Cid cid, int number_packets) override;
 
  private:
   LowerQueueUpEnd* link_queue_up_end_;
   os::Handler* handler_;
-
-  struct ChannelQueueEndAndBuffer {
-    ChannelQueueEndAndBuffer(os::Handler* handler, UpperQueueDownEnd* queue_end, Fifo* scheduler, Cid channel_id,
-                             Cid remote_channel_id)
-        : handler_(handler), queue_end_(queue_end), scheduler_(scheduler), channel_id_(channel_id),
-          remote_channel_id_(remote_channel_id) {
-      try_register_dequeue();
-    }
-    os::Handler* handler_;
-    UpperQueueDownEnd* queue_end_;
-    constexpr static int kBufferSize = 1;
-    std::queue<std::unique_ptr<UpperDequeue>> dequeue_buffer_;
-    Fifo* scheduler_;
-    Cid channel_id_;
-    Cid remote_channel_id_;
-    bool is_dequeue_registered_ = false;
-
-    void try_register_dequeue();
-    void dequeue_callback();
-    ~ChannelQueueEndAndBuffer();
-  };
-
-  std::unordered_map<Cid, ChannelQueueEndAndBuffer> channel_queue_end_map_;
-  std::queue<Cid> next_to_dequeue_;
+  std::unordered_map<Cid, Segmenter> segmenter_map_;
+  std::queue<std::pair<Cid, int>> next_to_dequeue_and_num_packets;
 
   bool link_queue_enqueue_registered_ = false;
   void try_register_link_queue_enqueue();
diff --git a/gd/l2cap/internal/scheduler_fifo_test.cc b/gd/l2cap/internal/scheduler_fifo_test.cc
index 85ef10f..e6d4f78 100644
--- a/gd/l2cap/internal/scheduler_fifo_test.cc
+++ b/gd/l2cap/internal/scheduler_fifo_test.cc
@@ -19,7 +19,6 @@
 #include <gtest/gtest.h>
 #include <future>
 
-#include "l2cap/l2cap_packets.h"
 #include "os/handler.h"
 #include "os/queue.h"
 #include "os/thread.h"
diff --git a/gd/l2cap/internal/scheduler_mock.h b/gd/l2cap/internal/scheduler_mock.h
index 616d156..be7dedb 100644
--- a/gd/l2cap/internal/scheduler_mock.h
+++ b/gd/l2cap/internal/scheduler_mock.h
@@ -25,13 +25,11 @@
 namespace internal {
 namespace testing {
 
-using hci::testing::MockAclConnection;
-
 class MockScheduler : public Scheduler {
  public:
   MOCK_METHOD(void, AttachChannel, (Cid cid, UpperQueueDownEnd* channel_down_end, Cid remote_cid), (override));
   MOCK_METHOD(void, DetachChannel, (Cid cid), (override));
-  MOCK_METHOD(LowerQueueUpEnd*, GetLowerQueueUpEnd, (), (override, const));
+  MOCK_METHOD(void, NotifyPacketsReady, (Cid cid, int number_packet), (override));
 };
 
 }  // namespace testing
diff --git a/gd/l2cap/internal/segmenter.cc b/gd/l2cap/internal/segmenter.cc
new file mode 100644
index 0000000..3b658db
--- /dev/null
+++ b/gd/l2cap/internal/segmenter.cc
@@ -0,0 +1,78 @@
+/*
+ * 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 <string>
+#include <unordered_map>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/segmenter.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+Segmenter::Segmenter(os::Handler* handler, UpperQueueDownEnd* queue_end, Scheduler* scheduler, Cid channel_id,
+                     Cid remote_channel_id)
+    : handler_(handler), queue_end_(queue_end), scheduler_(scheduler), channel_id_(channel_id),
+      remote_channel_id_(remote_channel_id) {
+  try_register_dequeue();
+}
+
+Segmenter::~Segmenter() {
+  if (is_dequeue_registered_) {
+    queue_end_->UnregisterDequeue();
+  }
+}
+
+void Segmenter::NotifyPacketSent() {
+  try_register_dequeue();
+}
+
+std::unique_ptr<Segmenter::UpperDequeue> Segmenter::GetNextPacket() {
+  ASSERT_LOG(!pdu_buffer_.empty(), "No packet is available");
+  auto packet = std::move(pdu_buffer_.front());
+  pdu_buffer_.pop();
+  return packet;
+}
+
+void Segmenter::try_register_dequeue() {
+  if (is_dequeue_registered_) {
+    return;
+  }
+  queue_end_->RegisterDequeue(handler_, common::Bind(&Segmenter::dequeue_callback, common::Unretained(this)));
+  is_dequeue_registered_ = true;
+}
+
+void Segmenter::dequeue_callback() {
+  auto packet = queue_end_->TryDequeue();
+  ASSERT(packet != nullptr);
+  // TODO(hsz): Construct PDU(s) according to channel mode.
+  auto pdu = BasicFrameBuilder::Create(remote_channel_id_, std::move(packet));
+  pdu_buffer_.emplace(std::move(pdu));
+  queue_end_->UnregisterDequeue();
+  is_dequeue_registered_ = false;
+  scheduler_->NotifyPacketsReady(channel_id_, 1);
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/segmenter.h b/gd/l2cap/internal/segmenter.h
new file mode 100644
index 0000000..e04c49a
--- /dev/null
+++ b/gd/l2cap/internal/segmenter.h
@@ -0,0 +1,74 @@
+/*
+ * 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 <string>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class Scheduler;
+
+/**
+ * A middle layer between L2CAP channel and outgoing packet scheduler.
+ * Fetches data (SDU) from an L2CAP channel queue end, handles L2CAP segmentation, and gives data to L2CAP scheduler.
+ */
+class Segmenter {
+ public:
+  using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+  using UpperDequeue = packet::BasePacketBuilder;
+  using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+
+  Segmenter(os::Handler* handler, UpperQueueDownEnd* queue_end, Scheduler* scheduler, Cid cid, Cid remote_cid);
+  ~Segmenter();
+
+  /**
+   * Callback from scheduler to indicate that scheduler already dequeued a packet from segmenter's queue.
+   * Segmenter can continue dequeuing from channel queue end.
+   */
+  void NotifyPacketSent();
+
+  /**
+   * Called by the scheduler to return the next PDU to be sent
+   */
+  std::unique_ptr<UpperDequeue> GetNextPacket();
+
+ private:
+  os::Handler* handler_;
+  UpperQueueDownEnd* queue_end_;
+  std::queue<std::unique_ptr<UpperDequeue>> pdu_buffer_;
+  Scheduler* scheduler_;
+  const Cid channel_id_;
+  const Cid remote_channel_id_;
+  bool is_dequeue_registered_ = false;
+
+  void try_register_dequeue();
+  void dequeue_callback();
+};
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/segmenter_test.cc b/gd/l2cap/internal/segmenter_test.cc
new file mode 100644
index 0000000..bf12c60
--- /dev/null
+++ b/gd/l2cap/internal/segmenter_test.cc
@@ -0,0 +1,99 @@
+/*
+ * 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/segmenter.h"
+
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/scheduler.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+  auto raw_builder = std::make_unique<packet::RawBuilder>();
+  raw_builder->AddOctets(payload);
+  return raw_builder;
+}
+
+class FakeScheduler : public Scheduler {
+ public:
+  void NotifyPacketsReady(Cid cid, int number_packets) override {
+    on_packets_ready_(cid, number_packets);
+  }
+
+  void SetOnPacketsReady(std::function<void(Cid cid, int number_packets)> callback) {
+    on_packets_ready_ = callback;
+  }
+  std::function<void(Cid cid, int number_packets)> on_packets_ready_;
+};
+
+class L2capSegmenterTest : public ::testing::Test {
+ public:
+  std::unique_ptr<Segmenter::UpperDequeue> enqueue_callback() {
+    auto packet_one = CreateSdu({1, 2, 3});
+    channel_queue_.GetUpEnd()->UnregisterEnqueue();
+    return packet_one;
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    user_handler_ = new os::Handler(thread_);
+    queue_handler_ = new os::Handler(thread_);
+    segmenter_ = new Segmenter(queue_handler_, channel_queue_.GetDownEnd(), &scheduler_, 0x41, 0x41);
+  }
+
+  void TearDown() override {
+    delete segmenter_;
+    queue_handler_->Clear();
+    user_handler_->Clear();
+    delete queue_handler_;
+    delete user_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* user_handler_ = nullptr;
+  os::Handler* queue_handler_ = nullptr;
+  common::BidiQueue<Segmenter::UpperEnqueue, Segmenter::UpperDequeue> channel_queue_{10};
+  Segmenter* segmenter_ = nullptr;
+  FakeScheduler scheduler_;
+};
+
+TEST_F(L2capSegmenterTest, send_packet) {
+  auto packet_one = CreateSdu({1, 2, 3});
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  scheduler_.SetOnPacketsReady([&promise](Cid cid, int number_packets) { promise.set_value(); });
+  channel_queue_.GetUpEnd()->RegisterEnqueue(
+      queue_handler_, common::Bind(&L2capSegmenterTest::enqueue_callback, common::Unretained(this)));
+  auto status = future.wait_for(std::chrono::milliseconds(3));
+  EXPECT_EQ(status, std::future_status::ready);
+  auto packet = segmenter_->GetNextPacket();
+  EXPECT_NE(packet, nullptr);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/mtu.h b/gd/l2cap/mtu.h
index 30c270c..fa9bc64 100644
--- a/gd/l2cap/mtu.h
+++ b/gd/l2cap/mtu.h
@@ -22,11 +22,9 @@
 
 using Mtu = uint16_t;
 
-constexpr Mtu kDefaultMinimumClassicMtu = 48;
-constexpr Mtu kDefaultMinimumLeMtu = 23;
 constexpr Mtu kMinimumClassicMtu = 48;
-constexpr Mtu kDefaultClassicMtu = 672;
 constexpr Mtu kMinimumLeMtu = 23;
+constexpr Mtu kDefaultClassicMtu = 672;
 
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.cc b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
index 492ddcc..77491d9 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
@@ -80,7 +80,7 @@
 void Beacon::IncomingPacket(model::packets::LinkLayerPacketView packet) {
   if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
       packet.GetType() == model::packets::PacketType::LE_SCAN) {
-    auto scan_response = model::packets::LeAdvertisementBuilder::Create(
+    auto scan_response = model::packets::LeScanResponseBuilder::Create(
         properties_.GetLeAddress(), packet.GetSourceAddress(),
         model::packets::AddressType::PUBLIC,
         model::packets::AdvertisementType::SCAN_RESPONSE,
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.cc b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
index e0b9f35..dd8d3ed 100644
--- a/vendor_libs/test_vendor_lib/model/devices/loopback.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
@@ -72,7 +72,7 @@
       packet.GetType() == model::packets::PacketType::LE_SCAN) {
     LOG_INFO("Got a scan");
 
-    auto scan_response = model::packets::LeAdvertisementBuilder::Create(
+    auto scan_response = model::packets::LeScanResponseBuilder::Create(
         properties_.GetLeAddress(), packet.GetSourceAddress(),
         model::packets::AddressType::PUBLIC,
         model::packets::AdvertisementType::SCAN_RESPONSE,