Merge "A2DP: Report codec configurations after retrieved all capabilities"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 7fb1636..380216c 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,3 +4,6 @@
 [Builtin Hooks]
 clang_format = true
 
+[Hook Scripts]
+aosp_first = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} ".*$"
+
diff --git a/audio_bluetooth_hw/Android.bp b/audio_bluetooth_hw/Android.bp
index 9cdd64a..de1effd 100644
--- a/audio_bluetooth_hw/Android.bp
+++ b/audio_bluetooth_hw/Android.bp
@@ -19,7 +19,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/audio_hal_interface/Android.bp b/audio_hal_interface/Android.bp
index 4b10435..94a77ff 100644
--- a/audio_hal_interface/Android.bp
+++ b/audio_hal_interface/Android.bp
@@ -19,7 +19,6 @@
         "android.hardware.bluetooth.audio@2.0",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
     ],
     static_libs: [
         "libosi",
@@ -46,7 +45,6 @@
         "libcutils",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
diff --git a/audio_hal_interface/client_interface.h b/audio_hal_interface/client_interface.h
index 11984aa..8ee2bb1 100644
--- a/audio_hal_interface/client_interface.h
+++ b/audio_hal_interface/client_interface.h
@@ -158,8 +158,9 @@
 
   static constexpr PcmParameters kInvalidPcmConfiguration = {
       .sampleRate = SampleRate::RATE_UNKNOWN,
+      .channelMode = ChannelMode::UNKNOWN,
       .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
-      .channelMode = ChannelMode::UNKNOWN};
+  };
 
  private:
   // Helper function to connect to an IBluetoothAudioProvider
diff --git a/binder/Android.bp b/binder/Android.bp
index e1f1592..e4beadb 100644
--- a/binder/Android.bp
+++ b/binder/Android.bp
@@ -75,6 +75,9 @@
         "-Wextra",
         "-Wno-unused-parameter",
     ],
+    sanitize: {
+        scs: true,
+    },
 }
 
 // AIDL interface between libbluetooth-binder and framework.jar
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index 6bda14b..d095682 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -35,12 +35,14 @@
  */
 interface IBluetooth
 {
+    @UnsupportedAppUsage
     boolean isEnabled();
     int getState();
     boolean enable();
     boolean enableNoAutoConnect();
     boolean disable();
 
+    @UnsupportedAppUsage
     String getAddress();
     ParcelUuid[] getUuids();
     boolean setName(in String name);
@@ -79,10 +81,12 @@
 
     String getRemoteName(in BluetoothDevice device);
     int getRemoteType(in BluetoothDevice device);
+    @UnsupportedAppUsage
     String getRemoteAlias(in BluetoothDevice device);
     boolean setRemoteAlias(in BluetoothDevice device, in String name);
     int getRemoteClass(in BluetoothDevice device);
     ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
+    @UnsupportedAppUsage
     boolean fetchRemoteUuids(in BluetoothDevice device);
     boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
     int getBatteryLevel(in BluetoothDevice device);
@@ -102,6 +106,7 @@
     int getSimAccessPermission(in BluetoothDevice device);
     boolean setSimAccessPermission(in BluetoothDevice device, int value);
 
+    @UnsupportedAppUsage
     void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
 
     void registerCallback(in IBluetoothCallback callback);
@@ -141,4 +146,7 @@
 
     void onLeServiceUp();
     void onBrEdrDown();
+
+    boolean connectAllEnabledProfiles(in BluetoothDevice device);
+    boolean disconnectAllEnabledProfiles(in BluetoothDevice device);
 }
diff --git a/binder/android/bluetooth/IBluetoothA2dp.aidl b/binder/android/bluetooth/IBluetoothA2dp.aidl
index 6606a1b..9cbd9ca 100644
--- a/binder/android/bluetooth/IBluetoothA2dp.aidl
+++ b/binder/android/bluetooth/IBluetoothA2dp.aidl
@@ -27,14 +27,20 @@
  */
 interface IBluetoothA2dp {
     // Public API
+    @UnsupportedAppUsage
     boolean connect(in BluetoothDevice device);
+    @UnsupportedAppUsage
     boolean disconnect(in BluetoothDevice device);
+    @UnsupportedAppUsage
     List<BluetoothDevice> getConnectedDevices();
+    @UnsupportedAppUsage
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    @UnsupportedAppUsage
     int getConnectionState(in BluetoothDevice device);
     boolean setActiveDevice(in BluetoothDevice device);
     BluetoothDevice getActiveDevice();
     boolean setPriority(in BluetoothDevice device, int priority);
+    @UnsupportedAppUsage
     int getPriority(in BluetoothDevice device);
     boolean isAvrcpAbsoluteVolumeSupported();
     oneway void setAvrcpAbsoluteVolume(int volume);
diff --git a/binder/android/bluetooth/IBluetoothGatt.aidl b/binder/android/bluetooth/IBluetoothGatt.aidl
index c9e1c4b..016eeff 100644
--- a/binder/android/bluetooth/IBluetoothGatt.aidl
+++ b/binder/android/bluetooth/IBluetoothGatt.aidl
@@ -71,8 +71,10 @@
     void registerSync(in ScanResult scanResult, in int skip, in int timeout, in IPeriodicAdvertisingCallback callback);
     void unregisterSync(in IPeriodicAdvertisingCallback callback);
 
+    @UnsupportedAppUsage
     void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
 
+    @UnsupportedAppUsage
     void unregisterClient(in int clientIf);
     void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport, in boolean opportunistic, in int phy);
     void clientDisconnect(in int clientIf, in String address);
diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl
index 0f6954c..c59cab1 100644
--- a/binder/android/bluetooth/IBluetoothHeadset.aidl
+++ b/binder/android/bluetooth/IBluetoothHeadset.aidl
@@ -29,8 +29,10 @@
  */
 interface IBluetoothHeadset {
     // Public API
+    @UnsupportedAppUsage
     List<BluetoothDevice> getConnectedDevices();
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+    @UnsupportedAppUsage
     int getConnectionState(in BluetoothDevice device);
     boolean startVoiceRecognition(in BluetoothDevice device);
     boolean stopVoiceRecognition(in BluetoothDevice device);
@@ -40,9 +42,13 @@
                                          in String arg);
 
     // Hidden API
+    @UnsupportedAppUsage
     boolean connect(in BluetoothDevice device);
+    @UnsupportedAppUsage
     boolean disconnect(in BluetoothDevice device);
+    @UnsupportedAppUsage
     boolean setPriority(in BluetoothDevice device, int priority);
+    @UnsupportedAppUsage
     int getPriority(in BluetoothDevice device);
     int getAudioState(in BluetoothDevice device);
     boolean isAudioOn();
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
index 2e12700..faf78d8 100644
--- a/binder/android/bluetooth/IBluetoothManager.aidl
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -31,13 +31,16 @@
 {
     IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
     void unregisterAdapter(in IBluetoothManagerCallback callback);
+    @UnsupportedAppUsage
     void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
+    @UnsupportedAppUsage
     void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
     boolean isEnabled();
     boolean enable(String packageName);
     boolean enableNoAutoConnect(String packageName);
     boolean disable(String packageName, boolean persist);
     int getState();
+    @UnsupportedAppUsage
     IBluetoothGatt getBluetoothGatt();
 
     boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
diff --git a/binder/android/bluetooth/IBluetoothMap.aidl b/binder/android/bluetooth/IBluetoothMap.aidl
index 562490e..1274787 100644
--- a/binder/android/bluetooth/IBluetoothMap.aidl
+++ b/binder/android/bluetooth/IBluetoothMap.aidl
@@ -26,7 +26,6 @@
 interface IBluetoothMap {
     int getState();
     BluetoothDevice getClient();
-    boolean connect(in BluetoothDevice device);
     boolean disconnect(in BluetoothDevice device);
     boolean isConnected(in BluetoothDevice device);
     List<BluetoothDevice> getConnectedDevices();
diff --git a/binder/android/bluetooth/IBluetoothPan.aidl b/binder/android/bluetooth/IBluetoothPan.aidl
index 16b6ddf..4052aa4 100644
--- a/binder/android/bluetooth/IBluetoothPan.aidl
+++ b/binder/android/bluetooth/IBluetoothPan.aidl
@@ -26,7 +26,7 @@
 interface IBluetoothPan {
     // Public API
     boolean isTetheringOn();
-    void setBluetoothTethering(boolean value);
+    void setBluetoothTethering(boolean value, String pkgName);
     boolean connect(in BluetoothDevice device);
     boolean disconnect(in BluetoothDevice device);
     List<BluetoothDevice> getConnectedDevices();
diff --git a/bta/Android.bp b/bta/Android.bp
index 0e7bfe8..824076e 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -34,7 +34,6 @@
 cc_library_static {
     name: "libbt-bta",
     defaults: ["fluoride_bta_defaults"],
-    cflags: ["-Wno-implicit-fallthrough"],
     srcs: [
         "ag/bta_ag_act.cc",
         "ag/bta_ag_api.cc",
diff --git a/bta/ag/bta_ag_cmd.cc b/bta/ag/bta_ag_cmd.cc
index bec5497..87b2a82 100644
--- a/bta/ag/bta_ag_cmd.cc
+++ b/bta/ag/bta_ag_cmd.cc
@@ -782,9 +782,11 @@
  ******************************************************************************/
 static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) {
   char* p_token = strtok(val->str, ",");
+  if (p_token == nullptr) return false;
   uint16_t rcv_ind_id = atoi(p_token);
 
   p_token = strtok(nullptr, ",");
+  if (p_token == nullptr) return false;
   uint16_t rcv_ind_val = atoi(p_token);
 
   APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id,
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index f70027f..f7bb8be 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -564,8 +564,8 @@
   if (p_scb->state == BTA_AG_INIT_ST) {
     LOG(INFO) << __func__ << ": Resume connection to " << p_scb->peer_addr
               << ", handle" << bta_ag_scb_to_idx(p_scb);
-    tBTA_AG_DATA open_data = {.api_open.bd_addr = p_scb->peer_addr,
-                              .api_open.sec_mask = p_scb->cli_sec_mask};
+    tBTA_AG_DATA open_data = {.api_open = {.bd_addr = p_scb->peer_addr,
+                                           .sec_mask = p_scb->cli_sec_mask}};
     bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
   } else {
     VLOG(1) << __func__ << ": device " << p_scb->peer_addr
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index ba955d3..88b3bdb 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -87,7 +87,7 @@
     } else {
       event = BTA_AG_DISC_INT_RES_EVT;
     }
-    tBTA_AG_DATA disc_result = {.disc_result.status = status};
+    tBTA_AG_DATA disc_result = {.disc_result = {.status = status}};
     do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx,
                                             event, disc_result));
   }
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index aa4a1e4..f7867d3 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -965,7 +965,7 @@
  *
  ******************************************************************************/
 void bta_av_config_ind(tBTA_AV_SCB* p_scb, tBTA_AV_DATA* p_data) {
-  tBTA_AV_CI_SETCONFIG setconfig;
+  tBTA_AV_CI_SETCONFIG setconfig{};
   tAVDT_SEP_INFO* p_info;
   const AvdtpSepConfig* p_evt_cfg = &p_data->str_msg.cfg;
   uint8_t psc_mask = (p_evt_cfg->psc_mask | p_scb->cfg.psc_mask);
@@ -2102,6 +2102,8 @@
   uint8_t m_pt = 0x60;
   tAVDT_DATA_OPT_MASK opt;
 
+  if (!p_scb->started) return;
+
   if (p_scb->cong) return;
 
   if (p_scb->use_rtp_header_marker_bit) {
@@ -3107,7 +3109,7 @@
   ARRAY_TO_STREAM(p_param, offload_start->codec_info,
                   (int8_t)sizeof(offload_start->codec_info));
   p_scb->offload_started = true;
-  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, p_param - param,
+  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP, p_param - param,
                             param, offload_vendor_callback);
 }
 
@@ -3115,7 +3117,7 @@
   uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
   APPL_TRACE_DEBUG("%s", __func__);
   param[0] = VS_HCI_A2DP_OFFLOAD_STOP;
-  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, 1, param,
+  BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP, 1, param,
                             offload_vendor_callback);
 }
 /*******************************************************************************
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index 34516fc..e33635e 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -243,9 +243,7 @@
   enable.features = bta_av_cb.features;
 
   /* Register for SCO change event */
-  if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) {
-    bta_sys_sco_register(bta_av_sco_chg_cback);
-  }
+  bta_sys_sco_register(bta_av_sco_chg_cback);
 
   /* call callback with enable event */
   tBTA_AV bta_av_data;
@@ -986,16 +984,20 @@
   int i;
   tBTA_AV_API_STOP stop;
 
-  APPL_TRACE_DEBUG("%s: id:%d status:%d", __func__, id, status);
+  LOG(INFO) << __func__ << ": status=" << +status << ", num_links=" << +id;
   if (id) {
     bta_av_cb.sco_occupied = true;
 
+    if (bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD) {
+      return;
+    }
+
     /* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */
     for (i = 0; i < BTA_AV_NUM_STRS; i++) {
       p_scb = bta_av_cb.p_scb[i];
 
       if (p_scb && p_scb->co_started && (!p_scb->sco_suspend)) {
-        APPL_TRACE_DEBUG("%s: suspending scb:%d", __func__, i);
+        VLOG(1) << __func__ << ": suspending scb:" << i;
         /* scb is used and started, not suspended automatically */
         p_scb->sco_suspend = true;
         stop.flush = false;
@@ -1007,12 +1009,16 @@
   } else {
     bta_av_cb.sco_occupied = false;
 
+    if (bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD) {
+      return;
+    }
+
     for (i = 0; i < BTA_AV_NUM_STRS; i++) {
       p_scb = bta_av_cb.p_scb[i];
 
       if (p_scb && p_scb->sco_suspend) /* scb is used and suspended for SCO */
       {
-        APPL_TRACE_DEBUG("%s: starting scb:%d", __func__, i);
+        VLOG(1) << __func__ << ": starting scb:" << i;
         bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
       }
     }
@@ -1108,8 +1114,10 @@
                   "%s: peer %s BTM_SwitchRole(BTM_ROLE_MASTER) error: %d",
                   __func__, p_scb->PeerAddress().ToString().c_str(), status);
       }
-      is_ok = false;
-      p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+      if (status != BTM_MODE_UNSUPPORTED && status != BTM_DEV_BLACKLISTED) {
+        is_ok = false;
+        p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
+      }
     }
   }
 
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 6432eb2..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"
@@ -1356,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)) {
@@ -1771,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 &
@@ -1945,10 +1947,13 @@
     APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__,
                      bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
   }
-  if ((bta_dm_search_cb.p_btm_inq_info) &&
-      (bta_dm_search_cb.p_btm_inq_info->results.device_type ==
-       BT_DEVICE_TYPE_BLE) &&
-      (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) {
+  if (((bta_dm_search_cb.p_btm_inq_info) &&
+       (bta_dm_search_cb.p_btm_inq_info->results.device_type ==
+        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))) {
     /* Do not perform RNR for LE devices at inquiry complete*/
     bta_dm_search_cb.name_discover_done = true;
   }
@@ -2504,7 +2509,7 @@
       sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps;
       sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
 
-    /* continue to next case */
+      [[fallthrough]];
     /* Passkey entry mode, mobile device with output capability is very
         unlikely to receive key request, so skip this event */
     /*case BTM_SP_KEY_REQ_EVT: */
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 438f329..e1e2cad 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -130,9 +130,9 @@
         {BTA_ID_CG, BTA_ALL_APP_ID, 1},     /* cg resue ct spec table */
         {BTA_ID_DG, BTA_ALL_APP_ID, 2},     /* dg spec table */
         {BTA_ID_AV, BTA_ALL_APP_ID, 4},     /* av spec table */
-        {BTA_ID_AVK, BTA_ALL_APP_ID, 12},   /* avk spec table */
-        {BTA_ID_FTC, BTA_ALL_APP_ID, 6},    /* ftc spec table */
-        {BTA_ID_FTS, BTA_ALL_APP_ID, 7},    /* fts spec table */
+        {BTA_ID_AVK, BTA_ALL_APP_ID, 13},   /* avk spec table */
+        {BTA_ID_FTC, BTA_ALL_APP_ID, 7},    /* ftc spec table */
+        {BTA_ID_FTS, BTA_ALL_APP_ID, 8},    /* fts spec table */
         {BTA_ID_HD, BTA_ALL_APP_ID, 3},     /* hd spec table */
         {BTA_ID_HH, BTA_HH_APP_ID_JOY, 5},  /* app BTA_HH_APP_ID_JOY,
                                                similar to hh spec table */
@@ -140,19 +140,19 @@
                                                similar to hh spec table */
         {BTA_ID_HH, BTA_ALL_APP_ID, 6},     /* hh spec table */
         {BTA_ID_PBC, BTA_ALL_APP_ID, 2},    /* reuse dg spec table */
-        {BTA_ID_PBS, BTA_ALL_APP_ID, 7},    /* reuse fts spec table */
-        {BTA_ID_OPC, BTA_ALL_APP_ID, 6},    /* reuse ftc spec table */
-        {BTA_ID_OPS, BTA_ALL_APP_ID, 7},    /* reuse fts spec table */
-        {BTA_ID_MSE, BTA_ALL_APP_ID, 7},    /* reuse fts spec table */
+        {BTA_ID_PBS, BTA_ALL_APP_ID, 8},    /* reuse fts spec table */
+        {BTA_ID_OPC, BTA_ALL_APP_ID, 7},    /* reuse ftc spec table */
+        {BTA_ID_OPS, BTA_ALL_APP_ID, 8},    /* reuse fts spec table */
+        {BTA_ID_MSE, BTA_ALL_APP_ID, 8},    /* reuse fts spec table */
         {BTA_ID_JV, BTA_JV_PM_ID_1,
-         6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
-        {BTA_ID_JV, BTA_ALL_APP_ID, 7},     /* reuse fts spec table */
-        {BTA_ID_HL, BTA_ALL_APP_ID, 8},     /* reuse fts spec table */
-        {BTA_ID_PAN, BTUI_PAN_ID_PANU, 9},  /* PANU spec table */
-        {BTA_ID_PAN, BTUI_PAN_ID_NAP, 10},  /* NAP spec table */
-        {BTA_ID_HS, BTA_ALL_APP_ID, 11},    /* HS spec table */
-        {BTA_ID_GATTC, BTA_ALL_APP_ID, 13}, /* gattc spec table */
-        {BTA_ID_GATTS, BTA_ALL_APP_ID, 14}  /* gatts spec table */
+         7}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
+        {BTA_ID_JV, BTA_ALL_APP_ID, 8},     /* reuse fts spec table */
+        {BTA_ID_HL, BTA_ALL_APP_ID, 9},     /* reuse fts spec table */
+        {BTA_ID_PAN, BTUI_PAN_ID_PANU, 10}, /* PANU spec table */
+        {BTA_ID_PAN, BTUI_PAN_ID_NAP, 11},  /* NAP spec table */
+        {BTA_ID_HS, BTA_ALL_APP_ID, 12},    /* HS spec table */
+        {BTA_ID_GATTC, BTA_ALL_APP_ID, 14}, /* gattc spec table */
+        {BTA_ID_GATTS, BTA_ALL_APP_ID, 15}  /* gatts spec table */
 };
 
 tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index b009e5a..3ff55b1 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -213,7 +213,7 @@
   }
 
   /* remove bg connection associated with this rcb */
-  for (uint8_t i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
+  for (uint8_t i = 0; i < BTM_GetWhiteListSize(); i++) {
     if (!bta_gattc_cb.bg_track[i].in_use) continue;
 
     if (bta_gattc_cb.bg_track[i].cif_mask & (1 << (p_clreg->client_if - 1))) {
diff --git a/bta/gatt/bta_gattc_api.cc b/bta/gatt/bta_gattc_api.cc
index 9b0bd9e..829084c 100644
--- a/bta/gatt/bta_gattc_api.cc
+++ b/bta/gatt/bta_gattc_api.cc
@@ -269,7 +269,7 @@
  * Returns          returns list of gatt::Service or NULL.
  *
  ******************************************************************************/
-const std::vector<gatt::Service>* BTA_GATTC_GetServices(uint16_t conn_id) {
+const std::list<gatt::Service>* BTA_GATTC_GetServices(uint16_t conn_id) {
   return bta_gattc_get_services(conn_id);
 }
 
diff --git a/bta/gatt/bta_gattc_cache.cc b/bta/gatt/bta_gattc_cache.cc
index 25b85ba..eed1d67 100644
--- a/bta/gatt/bta_gattc_cache.cc
+++ b/bta/gatt/bta_gattc_cache.cc
@@ -120,7 +120,7 @@
 }
 
 const Service* bta_gattc_find_matching_service(
-    const std::vector<Service>& services, uint16_t handle) {
+    const std::list<Service>& services, uint16_t handle) {
   for (const Service& service : services) {
     if (handle >= service.handle && handle <= service.end_handle)
       return &service;
@@ -419,14 +419,13 @@
   }
 }
 
-const std::vector<Service>* bta_gattc_get_services_srcb(
-    tBTA_GATTC_SERV* p_srcb) {
+const std::list<Service>* bta_gattc_get_services_srcb(tBTA_GATTC_SERV* p_srcb) {
   if (!p_srcb || p_srcb->gatt_database.IsEmpty()) return NULL;
 
   return &p_srcb->gatt_database.Services();
 }
 
-const std::vector<Service>* bta_gattc_get_services(uint16_t conn_id) {
+const std::list<Service>* bta_gattc_get_services(uint16_t conn_id) {
   tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id);
 
   if (p_clcb == NULL) return NULL;
@@ -438,14 +437,14 @@
 
 const Service* bta_gattc_get_service_for_handle_srcb(tBTA_GATTC_SERV* p_srcb,
                                                      uint16_t handle) {
-  const std::vector<Service>* services = bta_gattc_get_services_srcb(p_srcb);
+  const std::list<Service>* services = bta_gattc_get_services_srcb(p_srcb);
   if (services == NULL) return NULL;
   return bta_gattc_find_matching_service(*services, handle);
 }
 
 const Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
                                                 uint16_t handle) {
-  const std::vector<Service>* services = bta_gattc_get_services(conn_id);
+  const std::list<Service>* services = bta_gattc_get_services(conn_id);
   if (services == NULL) return NULL;
 
   return bta_gattc_find_matching_service(*services, handle);
@@ -556,7 +555,7 @@
 /*******************************************************************************
  * Returns          number of elements inside db from start_handle to end_handle
  ******************************************************************************/
-static size_t bta_gattc_get_db_size(const std::vector<Service>& services,
+static size_t bta_gattc_get_db_size(const std::list<Service>& services,
                                     uint16_t start_handle,
                                     uint16_t end_handle) {
   if (services.empty()) return 0;
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index 6ee962d..45a54c3 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -71,9 +71,9 @@
 #define BTA_GATTC_CL_MAX 32
 #endif
 
-/* max known devices GATTC can support */
+/* max known devices GATTC can support in Bluetooth spec */
 #ifndef BTA_GATTC_KNOWN_SR_MAX
-#define BTA_GATTC_KNOWN_SR_MAX 10
+#define BTA_GATTC_KNOWN_SR_MAX 255
 #endif
 
 #define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
@@ -426,8 +426,7 @@
                                                    uint8_t disc_type);
 extern void bta_gattc_search_service(tBTA_GATTC_CLCB* p_clcb,
                                      bluetooth::Uuid* p_uuid);
-extern const std::vector<gatt::Service>* bta_gattc_get_services(
-    uint16_t conn_id);
+extern const std::list<gatt::Service>* bta_gattc_get_services(uint16_t conn_id);
 extern const gatt::Service* bta_gattc_get_service_for_handle(uint16_t conn_id,
                                                              uint16_t handle);
 const gatt::Characteristic* bta_gattc_get_characteristic_srcb(
diff --git a/bta/gatt/bta_gattc_queue.cc b/bta/gatt/bta_gattc_queue.cc
index 6d9fff3..6d8f57c 100644
--- a/bta/gatt/bta_gattc_queue.cc
+++ b/bta/gatt/bta_gattc_queue.cc
@@ -171,9 +171,9 @@
                                        GATT_WRITE_OP_CB cb, void* cb_data) {
   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
                                     .handle = handle,
-                                    .write_type = write_type,
                                     .write_cb = cb,
                                     .write_cb_data = cb_data,
+                                    .write_type = write_type,
                                     .value = std::move(value)});
   gatt_execute_next_op(conn_id);
 }
@@ -184,9 +184,9 @@
                                    GATT_WRITE_OP_CB cb, void* cb_data) {
   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
                                     .handle = handle,
-                                    .write_type = write_type,
                                     .write_cb = cb,
                                     .write_cb_data = cb_data,
+                                    .write_type = write_type,
                                     .value = std::move(value)});
   gatt_execute_next_op(conn_id);
 }
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index 2c8e5fd..d0b45c1 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -224,7 +224,7 @@
   tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
   uint8_t i;
 
-  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+  for (i = 0; i < BTM_GetWhiteListSize(); i++, p_srcb++) {
     if (p_srcb->in_use && p_srcb->server_bda == bda) return p_srcb;
   }
   return NULL;
@@ -243,7 +243,7 @@
   tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
   uint8_t i;
 
-  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+  for (i = 0; i < BTM_GetWhiteListSize(); i++, p_srcb++) {
     if (p_srcb->server_bda == bda) return p_srcb;
   }
   return NULL;
@@ -279,7 +279,7 @@
   bool found = false;
   uint8_t i;
 
-  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_tcb++) {
+  for (i = 0; i < BTM_GetWhiteListSize(); i++, p_tcb++) {
     if (!p_tcb->in_use) {
       found = true;
       break;
@@ -409,7 +409,7 @@
   uint8_t i = 0;
   tBTA_GATTC_CIF_MASK* p_cif_mask;
 
-  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+  for (i = 0; i < BTM_GetWhiteListSize(); i++, p_bg_tck++) {
     if (p_bg_tck->in_use && ((p_bg_tck->remote_bda == remote_bda_ptr) ||
                              (p_bg_tck->remote_bda.IsEmpty()))) {
       p_cif_mask = &p_bg_tck->cif_mask;
@@ -437,7 +437,7 @@
   } else /* adding a new device mask */
   {
     for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0];
-         i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+         i < BTM_GetWhiteListSize(); i++, p_bg_tck++) {
       if (!p_bg_tck->in_use) {
         p_bg_tck->in_use = true;
         p_bg_tck->remote_bda = remote_bda_ptr;
@@ -468,7 +468,7 @@
   uint8_t i = 0;
   bool is_bg_conn = false;
 
-  for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX && !is_bg_conn; i++, p_bg_tck++) {
+  for (i = 0; i < BTM_GetWhiteListSize() && !is_bg_conn; i++, p_bg_tck++) {
     if (p_bg_tck->in_use && (p_bg_tck->remote_bda == remote_bda ||
                              p_bg_tck->remote_bda.IsEmpty())) {
       if (((p_bg_tck->cif_mask & (1 << (client_if - 1))) != 0) &&
diff --git a/bta/gatt/database.cc b/bta/gatt/database.cc
index 5f99d55..58f7056 100644
--- a/bta/gatt/database.cc
+++ b/bta/gatt/database.cc
@@ -21,6 +21,7 @@
 #include "stack/include/gattdefs.h"
 
 #include <base/logging.h>
+#include <list>
 #include <memory>
 #include <sstream>
 
@@ -39,7 +40,7 @@
 }
 }  // namespace
 
-Service* FindService(std::vector<Service>& services, uint16_t handle) {
+Service* FindService(std::list<Service>& services, uint16_t handle) {
   for (Service& service : services) {
     if (handle >= service.handle && handle <= service.end_handle)
       return &service;
@@ -126,11 +127,12 @@
   for (; it != nv_attr.cend(); ++it) {
     const auto& attr = *it;
     if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
-    result.services.emplace_back(
-        Service{.handle = attr.handle,
-                .end_handle = attr.value.service.end_handle,
-                .is_primary = (attr.type == PRIMARY_SERVICE),
-                .uuid = attr.value.service.uuid});
+    result.services.emplace_back(Service{
+        .handle = attr.handle,
+        .uuid = attr.value.service.uuid,
+        .is_primary = (attr.type == PRIMARY_SERVICE),
+        .end_handle = attr.value.service.end_handle,
+    });
   }
 
   auto current_service_it = result.services.begin();
@@ -167,11 +169,12 @@
           .end_handle = attr.value.included_service.end_handle,
       });
     } else if (attr.type == CHARACTERISTIC) {
-      current_service_it->characteristics.emplace_back(
-          Characteristic{.declaration_handle = attr.handle,
-                         .value_handle = attr.value.characteristic.value_handle,
-                         .properties = attr.value.characteristic.properties,
-                         .uuid = attr.value.characteristic.uuid});
+      current_service_it->characteristics.emplace_back(Characteristic{
+          .declaration_handle = attr.handle,
+          .uuid = attr.value.characteristic.uuid,
+          .value_handle = attr.value.characteristic.value_handle,
+          .properties = attr.value.characteristic.properties,
+      });
 
     } else {
       current_service_it->characteristics.back().descriptors.emplace_back(
@@ -182,4 +185,4 @@
   return result;
 }
 
-}  // namespace gatt
\ No newline at end of file
+}  // namespace gatt
diff --git a/bta/gatt/database.h b/bta/gatt/database.h
index 1e74809..d1ba836 100644
--- a/bta/gatt/database.h
+++ b/bta/gatt/database.h
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <list>
 #include <set>
 #include <string>
 #include <utility>
@@ -101,10 +102,10 @@
 
   /* Clear the GATT database. This method forces relocation to ensure no extra
    * space is used unnecesarly */
-  void Clear() { std::vector<Service>().swap(services); }
+  void Clear() { std::list<Service>().swap(services); }
 
   /* Return list of services available in this database */
-  const std::vector<Service>& Services() const { return services; }
+  const std::list<Service>& Services() const { return services; }
 
   std::string ToString() const;
 
@@ -116,11 +117,11 @@
   friend class DatabaseBuilder;
 
  private:
-  std::vector<Service> services;
+  std::list<Service> services;
 };
 
 /* Find a service that should contain handle. Helper method for internal use
  * inside gatt namespace.*/
-Service* FindService(std::vector<Service>& services, uint16_t handle);
+Service* FindService(std::list<Service>& services, uint16_t handle);
 
 }  // namespace gatt
diff --git a/bta/gatt/database_builder.cc b/bta/gatt/database_builder.cc
index ed065ab..98c0a27 100644
--- a/bta/gatt/database_builder.cc
+++ b/bta/gatt/database_builder.cc
@@ -32,10 +32,12 @@
   // general case optimization - we add services in order
   if (database.services.empty() ||
       database.services.back().end_handle < handle) {
-    database.services.emplace_back(Service{.handle = handle,
-                                           .end_handle = end_handle,
-                                           .is_primary = is_primary,
-                                           .uuid = uuid});
+    database.services.emplace_back(Service{
+        .handle = handle,
+        .uuid = uuid,
+        .is_primary = is_primary,
+        .end_handle = end_handle,
+    });
   } else {
     auto& vec = database.services;
 
@@ -45,10 +47,12 @@
         [](Service s, uint16_t handle) { return s.end_handle < handle; });
 
     // Insert new service just before it
-    vec.emplace(it, Service{.handle = handle,
-                            .end_handle = end_handle,
-                            .is_primary = is_primary,
-                            .uuid = uuid});
+    vec.emplace(it, Service{
+                        .handle = handle,
+                        .uuid = uuid,
+                        .is_primary = is_primary,
+                        .end_handle = end_handle,
+                    });
   }
 
   services_to_discover.insert({handle, end_handle});
@@ -90,11 +94,12 @@
                  << loghex(value_handle) << " is after service end_handle="
                  << loghex(service->end_handle);
 
-  service->characteristics.emplace_back(
-      Characteristic{.declaration_handle = handle,
-                     .value_handle = value_handle,
-                     .properties = properties,
-                     .uuid = uuid});
+  service->characteristics.emplace_back(Characteristic{
+      .declaration_handle = handle,
+      .uuid = uuid,
+      .value_handle = value_handle,
+      .properties = properties,
+  });
   return;
 }
 
diff --git a/bta/gatt/database_builder.h b/bta/gatt/database_builder.h
index 0913100..d2cc720 100644
--- a/bta/gatt/database_builder.h
+++ b/bta/gatt/database_builder.h
@@ -21,7 +21,6 @@
 #include "gatt/database.h"
 
 #include <utility>
-#include <vector>
 
 namespace gatt {
 
diff --git a/bta/hd/bta_hd_act.cc b/bta/hd/bta_hd_act.cc
index 0d677ee..a37a051 100644
--- a/bta/hd/bta_hd_act.cc
+++ b/bta/hd/bta_hd_act.cc
@@ -62,7 +62,7 @@
 
       case 0x85:  // Report ID
         *has_report_id = TRUE;
-
+        [[fallthrough]];
       default:
         ptr += (item & 0x03);
         break;
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index 7463909..75116f4 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -623,7 +623,7 @@
       return;
     }
 
-    const std::vector<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
+    const std::list<gatt::Service>* services = BTA_GATTC_GetServices(conn_id);
 
     const gatt::Service* service = nullptr;
     for (const gatt::Service& tmp : *services) {
diff --git a/bta/hf_client/bta_hf_client_sco.cc b/bta/hf_client/bta_hf_client_sco.cc
index 50820bd..faf970d 100644
--- a/bta/hf_client/bta_hf_client_sco.cc
+++ b/bta/hf_client/bta_hf_client_sco.cc
@@ -305,6 +305,8 @@
         case BTA_HF_CLIENT_SCO_LISTEN_E:
           /* create SCO listen connection */
           bta_hf_client_sco_create(client_cb, false);
+          /* TODO(b/143901894): Is this correct? */
+          [[fallthrough]];
 
         case BTA_HF_CLIENT_SCO_OPEN_E:
           /* remove listening connection */
diff --git a/bta/hh/bta_hh_le.cc b/bta/hh/bta_hh_le.cc
index eb87cdf..510e3a4 100644
--- a/bta/hh/bta_hh_le.cc
+++ b/bta/hh/bta_hh_le.cc
@@ -1490,7 +1490,7 @@
     return;
   }
 
-  const std::vector<gatt::Service>* services =
+  const std::list<gatt::Service>* services =
       BTA_GATTC_GetServices(p_data->conn_id);
 
   bool have_hid = false;
diff --git a/bta/include/bta_gatt_api.h b/bta/include/bta_gatt_api.h
index 9176501..41151f8 100644
--- a/bta/include/bta_gatt_api.h
+++ b/bta/include/bta_gatt_api.h
@@ -491,8 +491,7 @@
  * Returns          returns list of gatt::Service or NULL.
  *
  ******************************************************************************/
-extern const std::vector<gatt::Service>* BTA_GATTC_GetServices(
-    uint16_t conn_id);
+extern const std::list<gatt::Service>* BTA_GATTC_GetServices(uint16_t conn_id);
 
 /*******************************************************************************
  *
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 462ee9d..5cd8041 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -1885,16 +1885,16 @@
   static tL2CAP_FIXED_CHNL_REG fcr = {
       .pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
       .pL2CA_FixedData_Cb = fcchan_data_cbk,
-      .default_idle_tout = 0xffff,
       .fixed_chnl_opts =
           {
               .mode = L2CAP_FCR_BASIC_MODE,
+              .tx_win_sz = 1,
               .max_transmit = 0xFF,
               .rtrans_tout = 2000,
               .mon_tout = 12000,
               .mps = 670,
-              .tx_win_sz = 1,
           },
+      .default_idle_tout = 0xffff,
   };
 
   while (t && t->chan != chan) t = t->next;
diff --git a/bta/test/gatt/database_builder_sample_device_test.cc b/bta/test/gatt/database_builder_sample_device_test.cc
index bd4dabc..2bfaa04 100644
--- a/bta/test/gatt/database_builder_sample_device_test.cc
+++ b/bta/test/gatt/database_builder_sample_device_test.cc
@@ -19,6 +19,7 @@
 #include <gtest/gtest.h>
 
 #include <base/logging.h>
+#include <iterator>
 #include <utility>
 
 #include "gatt/database_builder.h"
@@ -223,64 +224,51 @@
   EXPECT_FALSE(builder.InProgress());
 
   // verify that the returned database matches what was discovered
-  EXPECT_EQ(result.Services()[0].handle, 0x0001);
-  EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
-  EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
-  EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
-  EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
-  EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
-  EXPECT_EQ(result.Services()[5].uuid, SERVICE_6_UUID);
+  auto service = result.Services().begin();
+  EXPECT_EQ(service->handle, 0x0001);
+  EXPECT_EQ(service->uuid, SERVICE_1_UUID);
 
-  EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
-            SERVICE_1_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[0].characteristics[1].uuid,
-            SERVICE_1_CHAR_2_UUID);
-  EXPECT_EQ(result.Services()[0].characteristics[2].uuid,
-            SERVICE_1_CHAR_3_UUID);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_1_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[1].uuid, SERVICE_1_CHAR_2_UUID);
+  EXPECT_EQ(service->characteristics[2].uuid, SERVICE_1_CHAR_3_UUID);
 
-  EXPECT_EQ(result.Services()[2].characteristics[0].uuid,
-            SERVICE_3_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[2].characteristics[0].descriptors[0].uuid,
+  service++;
+  EXPECT_EQ(service->uuid, SERVICE_2_UUID);
+
+  service++;
+  EXPECT_EQ(service->uuid, SERVICE_3_UUID);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_3_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[0].descriptors[0].uuid,
             SERVICE_3_CHAR_1_DESC_1_UUID);
 
-  EXPECT_EQ(result.Services()[3].characteristics[0].uuid,
-            SERVICE_4_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[1].uuid,
-            SERVICE_4_CHAR_2_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[2].uuid,
-            SERVICE_4_CHAR_3_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[3].uuid,
-            SERVICE_4_CHAR_4_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[4].uuid,
-            SERVICE_4_CHAR_5_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[5].uuid,
-            SERVICE_4_CHAR_6_UUID);
-  EXPECT_EQ(result.Services()[3].characteristics[5].descriptors[0].uuid,
+  service++;
+  EXPECT_EQ(service->uuid, SERVICE_4_UUID);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_4_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[1].uuid, SERVICE_4_CHAR_2_UUID);
+  EXPECT_EQ(service->characteristics[2].uuid, SERVICE_4_CHAR_3_UUID);
+  EXPECT_EQ(service->characteristics[3].uuid, SERVICE_4_CHAR_4_UUID);
+  EXPECT_EQ(service->characteristics[4].uuid, SERVICE_4_CHAR_5_UUID);
+  EXPECT_EQ(service->characteristics[5].uuid, SERVICE_4_CHAR_6_UUID);
+  EXPECT_EQ(service->characteristics[5].descriptors[0].uuid,
             SERVICE_4_CHAR_6_DESC_1_UUID);
 
-  EXPECT_EQ(result.Services()[4].characteristics[0].uuid,
-            SERVICE_5_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[1].uuid,
-            SERVICE_5_CHAR_2_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[2].uuid,
-            SERVICE_5_CHAR_3_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[3].uuid,
-            SERVICE_5_CHAR_4_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[4].uuid,
-            SERVICE_5_CHAR_5_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[5].uuid,
-            SERVICE_5_CHAR_6_UUID);
-  EXPECT_EQ(result.Services()[4].characteristics[6].uuid,
-            SERVICE_5_CHAR_7_UUID);
+  service++;
+  EXPECT_EQ(service->uuid, SERVICE_5_UUID);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_5_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[1].uuid, SERVICE_5_CHAR_2_UUID);
+  EXPECT_EQ(service->characteristics[2].uuid, SERVICE_5_CHAR_3_UUID);
+  EXPECT_EQ(service->characteristics[3].uuid, SERVICE_5_CHAR_4_UUID);
+  EXPECT_EQ(service->characteristics[4].uuid, SERVICE_5_CHAR_5_UUID);
+  EXPECT_EQ(service->characteristics[5].uuid, SERVICE_5_CHAR_6_UUID);
+  EXPECT_EQ(service->characteristics[6].uuid, SERVICE_5_CHAR_7_UUID);
 
-  EXPECT_EQ(result.Services()[5].characteristics[0].uuid,
-            SERVICE_6_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[5].characteristics[0].descriptors[0].uuid,
+  service++;
+  EXPECT_EQ(service->uuid, SERVICE_6_UUID);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_6_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[0].descriptors[0].uuid,
             SERVICE_6_CHAR_1_DESC_1_UUID);
-  EXPECT_EQ(result.Services()[5].characteristics[1].uuid,
-            SERVICE_6_CHAR_2_UUID);
-  EXPECT_EQ(result.Services()[5].characteristics[2].uuid,
-            SERVICE_6_CHAR_3_UUID);
+  EXPECT_EQ(service->characteristics[1].uuid, SERVICE_6_CHAR_2_UUID);
+  EXPECT_EQ(service->characteristics[2].uuid, SERVICE_6_CHAR_3_UUID);
 }
 
 }  // namespace gatt
\ No newline at end of file
diff --git a/bta/test/gatt/database_builder_test.cc b/bta/test/gatt/database_builder_test.cc
index fcafb49..0a7e928 100644
--- a/bta/test/gatt/database_builder_test.cc
+++ b/bta/test/gatt/database_builder_test.cc
@@ -19,6 +19,7 @@
 #include <gtest/gtest.h>
 
 #include <base/logging.h>
+#include <iterator>
 #include <utility>
 
 #include "gatt/database_builder.h"
@@ -59,10 +60,11 @@
   Database result = builder.Build();
 
   // verify that the returned database matches what was discovered
-  EXPECT_EQ(result.Services()[0].handle, 0x0001);
-  EXPECT_EQ(result.Services()[0].end_handle, 0x0001);
-  EXPECT_EQ(result.Services()[0].is_primary, true);
-  EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+  auto service = result.Services().begin();
+  EXPECT_EQ(service->handle, 0x0001);
+  EXPECT_EQ(service->end_handle, 0x0001);
+  EXPECT_EQ(service->is_primary, true);
+  EXPECT_EQ(service->uuid, SERVICE_1_UUID);
 }
 
 /* Verify adding service, characteristic and descriptor work */
@@ -79,21 +81,20 @@
   Database result = builder.Build();
 
   // verify that the returned database matches what was discovered
-  EXPECT_EQ(result.Services()[0].handle, 0x0001);
-  EXPECT_EQ(result.Services()[0].end_handle, 0x000f);
-  EXPECT_EQ(result.Services()[0].is_primary, true);
-  EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+  auto service = result.Services().begin();
+  EXPECT_EQ(service->handle, 0x0001);
+  EXPECT_EQ(service->end_handle, 0x000f);
+  EXPECT_EQ(service->is_primary, true);
+  EXPECT_EQ(service->uuid, SERVICE_1_UUID);
 
-  EXPECT_EQ(result.Services()[0].characteristics[0].uuid,
-            SERVICE_1_CHAR_1_UUID);
-  EXPECT_EQ(result.Services()[0].characteristics[0].declaration_handle, 0x0002);
-  EXPECT_EQ(result.Services()[0].characteristics[0].value_handle, 0x0003);
-  EXPECT_EQ(result.Services()[0].characteristics[0].properties, 0x02);
+  EXPECT_EQ(service->characteristics[0].uuid, SERVICE_1_CHAR_1_UUID);
+  EXPECT_EQ(service->characteristics[0].declaration_handle, 0x0002);
+  EXPECT_EQ(service->characteristics[0].value_handle, 0x0003);
+  EXPECT_EQ(service->characteristics[0].properties, 0x02);
 
-  EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].uuid,
+  EXPECT_EQ(service->characteristics[0].descriptors[0].uuid,
             SERVICE_1_CHAR_1_DESC_1_UUID);
-  EXPECT_EQ(result.Services()[0].characteristics[0].descriptors[0].handle,
-            0x0004);
+  EXPECT_EQ(service->characteristics[0].descriptors[0].handle, 0x0004);
 }
 
 /* This test verifies that DatabaseBuilder properly handle discovery of
@@ -139,27 +140,35 @@
   Database result = builder.Build();
 
   // verify that the returned database matches what was discovered
-  EXPECT_EQ(result.Services()[0].handle, 0x0001);
-  EXPECT_EQ(result.Services()[0].is_primary, true);
-  EXPECT_EQ(result.Services()[0].uuid, SERVICE_1_UUID);
+  auto service = result.Services().begin();
+  EXPECT_EQ(service->handle, 0x0001);
+  EXPECT_EQ(service->is_primary, true);
+  EXPECT_EQ(service->uuid, SERVICE_1_UUID);
 
-  EXPECT_EQ(result.Services()[1].handle, 0x0020);
-  EXPECT_EQ(result.Services()[1].end_handle, 0x002f);
-  EXPECT_EQ(result.Services()[1].uuid, SERVICE_2_UUID);
-  EXPECT_EQ(result.Services()[1].is_primary, false);
+  service++;
+  EXPECT_EQ(service->handle, 0x0020);
+  EXPECT_EQ(service->end_handle, 0x002f);
+  EXPECT_EQ(service->uuid, SERVICE_2_UUID);
+  EXPECT_EQ(service->is_primary, false);
 
-  EXPECT_EQ(result.Services()[2].handle, 0x0030);
-  EXPECT_EQ(result.Services()[2].end_handle, 0x003f);
-  EXPECT_EQ(result.Services()[2].uuid, SERVICE_3_UUID);
-  EXPECT_EQ(result.Services()[2].is_primary, true);
+  service++;
+  EXPECT_EQ(service->handle, 0x0030);
+  EXPECT_EQ(service->end_handle, 0x003f);
+  EXPECT_EQ(service->uuid, SERVICE_3_UUID);
+  EXPECT_EQ(service->is_primary, true);
 
-  EXPECT_EQ(result.Services()[3].handle, 0x0040);
-  EXPECT_EQ(result.Services()[3].uuid, SERVICE_4_UUID);
-  EXPECT_EQ(result.Services()[3].is_primary, false);
+  service++;
+  EXPECT_EQ(service->handle, 0x0040);
+  EXPECT_EQ(service->uuid, SERVICE_4_UUID);
+  EXPECT_EQ(service->is_primary, false);
 
-  EXPECT_EQ(result.Services()[4].handle, 0x0050);
-  EXPECT_EQ(result.Services()[4].uuid, SERVICE_5_UUID);
-  EXPECT_EQ(result.Services()[4].is_primary, true);
+  service++;
+  EXPECT_EQ(service->handle, 0x0050);
+  EXPECT_EQ(service->uuid, SERVICE_5_UUID);
+  EXPECT_EQ(service->is_primary, true);
+
+  service++;
+  ASSERT_EQ(service, result.Services().end());
 }
 
 }  // namespace gatt
\ No newline at end of file
diff --git a/btif/Android.bp b/btif/Android.bp
index 814cba7..6be1d81 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -24,6 +24,8 @@
     "system/bt/utils/include",
     "system/bt/include",
     "system/libhwbinder/include",
+    "system/security/keystore/include",
+    "hardware/interfaces/keymaster/4.0/support/include",
 ]
 
 // libbtif static library for target
@@ -71,6 +73,7 @@
         "src/btif_hf_client.cc",
         "src/btif_hh.cc",
         "src/btif_hd.cc",
+        "src/btif_keystore.cc",
         "src/btif_mce.cc",
         "src/btif_pan.cc",
         "src/btif_profile_queue.cc",
@@ -89,6 +92,9 @@
         "src/btif_util.cc",
         "src/stack_manager.cc",
     ],
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "libaudioclient",
         "libcutils",
@@ -99,10 +105,14 @@
         "android.hardware.bluetooth.a2dp@1.0",
         "android.hardware.bluetooth.audio@2.0",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "libutils",
         "libcrypto",
+        "android.hardware.keymaster@4.0",
+        "android.hardware.keymaster@3.0",
+        "libkeymaster4support",
+        "libkeystore_aidl",
+        "libkeystore_binder",
+        "libkeystore_parcelables",
     ],
     whole_static_libs: [
         "avrcp-target-service",
@@ -112,7 +122,6 @@
     ],
     cflags: [
         "-DBUILDCFG",
-        "-Wno-implicit-fallthrough",
     ],
 
 }
@@ -124,7 +133,10 @@
     defaults: ["fluoride_defaults"],
     test_suites: ["device-tests"],
     include_dirs: btifCommonIncludes,
-    srcs: ["test/btif_storage_test.cc"],
+    srcs: [
+        "test/btif_storage_test.cc",
+        "test/btif_keystore_test.cc"
+    ],
     header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "libaudioclient",
@@ -132,7 +144,6 @@
         "android.hardware.bluetooth.audio@2.0",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libprotobuf-cpp-lite",
         "libcutils",
@@ -169,6 +180,9 @@
         "libbluetooth-for-tests",
     ],
     cflags: ["-DBUILDCFG"],
+    sanitize: {
+        integer_overflow: true,
+    },
 }
 
 // btif profile queue unit tests for target
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index efaf6db..cec3f69 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -163,7 +163,29 @@
         APPL_TRACE_ERROR("%s: UHID_FEATURE: Invalid report type = %d", __func__,
                          ev.u.feature.rtype);
       break;
+    case UHID_SET_REPORT:
+      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
+          APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+                           __func__, ret, sizeof(ev.type) + sizeof(ev.u.set_report));
+            return -EFAULT;
+        }
 
+        APPL_TRACE_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d"
+                          , ev.u.set_report.rtype, ev.u.set_report.size);
+
+        if (ev.u.set_report.rtype == UHID_FEATURE_REPORT)
+            btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
+                              ev.u.set_report.size, ev.u.set_report.data);
+        else if (ev.u.set_report.rtype == UHID_OUTPUT_REPORT)
+            btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
+                              ev.u.set_report.size, ev.u.set_report.data);
+        else if(ev.u.set_report.rtype == UHID_INPUT_REPORT)
+            btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
+                              ev.u.set_report.size, ev.u.set_report.data);
+        else
+            APPL_TRACE_ERROR("%s:UHID_SET_REPORT: Invalid Report type = %d"
+                          , __func__, ev.u.set_report.rtype);
+        break;
     default:
       APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
   }
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
index 519fc9c..cef1aad 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -105,6 +105,19 @@
 
 /*******************************************************************************
  *
+ * Function         is_single_user_mode_
+ *
+ * Description      Checks if BT was enabled in single user mode. In this
+ *                  mode, use of keystore for key attestation of LTK is limitee
+ *                  to this mode defined by UserManager.
+ *
+ * Returns          bool
+ *
+ ******************************************************************************/
+bool is_single_user_mode(void);
+
+/*******************************************************************************
+ *
  * Function         btif_get_adapter_properties
  *
  * Description      Fetches all local adapter properties
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index a9cb228..a9d4cb6 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -100,7 +100,7 @@
 void btif_dm_get_ble_local_keys(tBTA_DM_BLE_LOCAL_KEY_MASK* p_key_mask,
                                 Octet16* p_er,
                                 tBTA_BLE_LOCAL_ID_KEYS* p_id_keys);
-void btif_dm_save_ble_bonding_keys(void);
+void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr);
 void btif_dm_remove_ble_bonding_keys(void);
 void btif_dm_ble_sec_req_evt(tBTA_DM_BLE_SEC_REQ* p_ble_req);
 
diff --git a/btif/include/btif_keystore.h b/btif/include/btif_keystore.h
new file mode 100644
index 0000000..cc06a98
--- /dev/null
+++ b/btif/include/btif_keystore.h
@@ -0,0 +1,78 @@
+/******************************************************************************
+ *
+ *  Copyright 2019 Google, Inc.
+ *
+ *  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 <base/logging.h>
+#include <keystore/keystore_client_impl.h>
+#include <mutex>
+
+#include "osi/include/alarm.h"
+#include "osi/include/allocator.h"
+#include "osi/include/compat.h"
+#include "osi/include/config.h"
+#include "osi/include/log.h"
+#include "osi/include/osi.h"
+#include "osi/include/properties.h"
+
+namespace bluetooth {
+/**
+ * Client wrapper to access AndroidKeystore.
+ *
+ * <p>Use to encrypt/decrypt data and store to disk.
+ */
+class BtifKeystore {
+ public:
+  /**
+   * @param keystore_client injected pre-created client object for keystore
+   */
+  BtifKeystore(keystore::KeystoreClient* keystore_client);
+
+  /**
+   * Encrypts given data
+   *
+   * <p>Returns a string representation of the encrypted data
+   *
+   * @param data to be encrypted
+   * @param flags for keystore
+   */
+  std::string Encrypt(const std::string& data, int32_t flags);
+
+  /**
+   * Returns a decrypted string representation of the encrypted data or empty
+   * string on error.
+   *
+   * @param input encrypted data
+   */
+  std::string Decrypt(const std::string& input_filename);
+
+  /**
+   * Check for existence of keystore key.
+   *
+   * This key can be cleared if a user manually wipes bluetooth storage data
+   * b/133214365
+   */
+  bool DoesKeyExist();
+
+ private:
+  std::unique_ptr<keystore::KeystoreClient> keystore_client_;
+  std::mutex api_mutex_;
+  keystore::KeyStoreNativeReturnCode GenerateKey(const std::string& name,
+                                                 int32_t flags,
+                                                 bool auth_bound);
+};
+
+}  // namespace bluetooth
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 1faca2d..ae13843 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -65,6 +65,7 @@
 #include "common/address_obfuscator.h"
 #include "common/metrics.h"
 #include "device/include/interop.h"
+#include "main/shim/shim.h"
 #include "osi/include/alarm.h"
 #include "osi/include/allocation_tracker.h"
 #include "osi/include/log.h"
@@ -81,6 +82,7 @@
 
 bt_callbacks_t* bt_hal_cbacks = NULL;
 bool restricted_mode = false;
+bool single_user_mode = false;
 
 /*******************************************************************************
  *  Externs
@@ -132,8 +134,16 @@
  *
  ****************************************************************************/
 
-static int init(bt_callbacks_t* callbacks) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+static int init(bt_callbacks_t* callbacks, bool start_restricted,
+                bool is_single_user_mode) {
+  LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__,
+           start_restricted, is_single_user_mode);
+
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    LOG_INFO(LOG_TAG, "%s Enable Gd bluetooth functionality", __func__);
+  } else {
+    LOG_INFO(LOG_TAG, "%s Preserving legacy bluetooth functionality", __func__);
+  }
 
   if (interface_ready()) return BT_STATUS_DONE;
 
@@ -142,16 +152,14 @@
 #endif
 
   bt_hal_cbacks = callbacks;
+  restricted_mode = start_restricted;
+  single_user_mode = is_single_user_mode;
   stack_manager_get_interface()->init_stack();
   btif_debug_init();
   return BT_STATUS_SUCCESS;
 }
 
-static int enable(bool start_restricted) {
-  LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);
-
-  restricted_mode = start_restricted;
-
+static int enable() {
   if (!interface_ready()) return BT_STATUS_NOT_READY;
 
   stack_manager_get_interface()->start_up_stack_async();
@@ -168,6 +176,7 @@
 static void cleanup(void) { stack_manager_get_interface()->clean_up_stack(); }
 
 bool is_restricted_mode() { return restricted_mode; }
+bool is_single_user_mode() { return single_user_mode; }
 
 static int get_adapter_properties(void) {
   /* sanity check */
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index bb1bc49..aa75d21 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -667,7 +667,6 @@
   LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
   LockGuard lock(g_mutex);
 
-  if (!btif_av_is_connected()) return;
   APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
   btif_a2dp_sink_cb.rx_focus_state = state;
   if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
diff --git a/btif/src/btif_bqr.cc b/btif/src/btif_bqr.cc
index 17253c5..3f53e74 100644
--- a/btif/src/btif_bqr.cc
+++ b/btif/src/btif_bqr.cc
@@ -294,7 +294,7 @@
   UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask);
   UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval_ms);
 
-  BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR_OPCODE_OCF, p_param - param,
+  BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR, p_param - param,
                             param, BqrVscCompleteCallback);
 }
 
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index c017c0f..ed24d7d 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -23,19 +23,22 @@
 #include <base/logging.h>
 #include <ctype.h>
 #include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
-#include <string>
-
 #include <mutex>
+#include <sstream>
+#include <string>
 
 #include "bt_types.h"
 #include "btcore/include/module.h"
 #include "btif_api.h"
 #include "btif_common.h"
 #include "btif_config_transcode.h"
+#include "btif_keystore.h"
 #include "btif_util.h"
 #include "common/address_obfuscator.h"
 #include "osi/include/alarm.h"
@@ -52,10 +55,18 @@
 #define FILE_TIMESTAMP "TimeCreated"
 #define FILE_SOURCE "FileSource"
 #define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS")
+#define DISABLED "disabled"
 static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
 
+constexpr int kBufferSize = 400 * 10;  // initial file is ~400B
+
+static bool use_key_attestation() {
+  return getuid() == AID_BLUETOOTH && is_single_user_mode();
+}
+
 #define BT_CONFIG_METRICS_SECTION "Metrics"
 #define BT_CONFIG_METRICS_SALT_256BIT "Salt256Bit"
+using bluetooth::BtifKeystore;
 using bluetooth::common::AddressObfuscator;
 
 // TODO(armansito): Find a better way than searching by a hardcoded path.
@@ -66,6 +77,8 @@
 #else   // !defined(OS_GENERIC)
 static const char* CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
 static const char* CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
+static const char* CONFIG_FILE_CHECKSUM_PATH = "/data/misc/bluedroid/bt_config.conf.encrypted-checksum";
+static const char* CONFIG_BACKUP_CHECKSUM_PATH = "/data/misc/bluedroid/bt_config.bak.encrypted-checksum";
 static const char* CONFIG_LEGACY_FILE_PATH =
     "/data/misc/bluedroid/bt_config.xml";
 #endif  // defined(OS_GENERIC)
@@ -77,7 +90,12 @@
 static void delete_config_files(void);
 static void btif_config_remove_unpaired(config_t* config);
 static void btif_config_remove_restricted(config_t* config);
-static std::unique_ptr<config_t> btif_config_open(const char* filename);
+static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename);
+
+// Key attestation
+static std::string hash_file(const char* filename);
+static std::string read_checksum_file(const char* filename);
+static void write_checksum_file(const char* filename, const std::string& hash);
 
 static enum ConfigSource {
   NOT_LOADED,
@@ -158,21 +176,26 @@
 static std::unique_ptr<config_t> config;
 static alarm_t* config_timer;
 
+static BtifKeystore btif_keystore(new keystore::KeystoreClientImpl);
+
 // Module lifecycle functions
 
 static future_t* init(void) {
   std::unique_lock<std::recursive_mutex> lock(config_lock);
 
-  if (is_factory_reset()) delete_config_files();
+  if (is_factory_reset() ||
+      (use_key_attestation() && !btif_keystore.DoesKeyExist()))
+    delete_config_files();
 
   std::string file_source;
 
-  config = btif_config_open(CONFIG_FILE_PATH);
+  config = btif_config_open(CONFIG_FILE_PATH, CONFIG_FILE_CHECKSUM_PATH);
   btif_config_source = ORIGINAL;
   if (!config) {
     LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
              __func__, CONFIG_FILE_PATH);
-    config = btif_config_open(CONFIG_BACKUP_PATH);
+    remove(CONFIG_FILE_CHECKSUM_PATH);
+    config = btif_config_open(CONFIG_BACKUP_PATH, CONFIG_BACKUP_CHECKSUM_PATH);
     btif_config_source = BACKUP;
     file_source = "Backup";
   }
@@ -180,6 +203,7 @@
     LOG_WARN(LOG_TAG,
              "%s unable to load backup; attempting to transcode legacy file.",
              __func__);
+    remove(CONFIG_BACKUP_CHECKSUM_PATH);
     config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH);
     btif_config_source = LEGACY;
     file_source = "Legacy";
@@ -239,7 +263,25 @@
   return future_new_immediate(FUTURE_FAIL);
 }
 
-static std::unique_ptr<config_t> btif_config_open(const char* filename) {
+static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename) {
+  // START KEY ATTESTATION
+  // Get hash of current file
+  std::string current_hash = hash_file(filename);
+  // Get stored hash
+  std::string stored_hash = read_checksum_file(checksum_filename);
+  if (stored_hash.empty()) {
+    LOG(ERROR) << __func__ << ": stored_hash=<empty>";
+    if (!current_hash.empty()) {
+      write_checksum_file(checksum_filename, current_hash);
+      stored_hash = read_checksum_file(checksum_filename);
+    }
+  }
+  // Compare hashes
+  if (current_hash != stored_hash) {
+    return nullptr;
+  }
+  // END KEY ATTESTATION
+
   std::unique_ptr<config_t> config = config_new(filename);
   if (!config) return nullptr;
 
@@ -413,6 +455,12 @@
 
   if (length > 0) CHECK(value != NULL);
 
+  size_t max_value = ((size_t)-1);
+  if (((max_value - 1) / 2) < length) {
+    LOG(ERROR) << __func__ << ": length too long";
+    return false;
+  }
+
   char* str = (char*)osi_calloc(length * 2 + 1);
 
   for (size_t i = 0; i < length; ++i) {
@@ -465,6 +513,13 @@
 
   bool ret = config_save(*config, CONFIG_FILE_PATH);
   btif_config_source = RESET;
+
+  // Save encrypted hash
+  std::string current_hash = hash_file(CONFIG_FILE_PATH);
+  if (!current_hash.empty()) {
+    write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
+  }
+
   return ret;
 }
 
@@ -482,9 +537,15 @@
 
   std::unique_lock<std::recursive_mutex> lock(config_lock);
   rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
+  rename(CONFIG_FILE_CHECKSUM_PATH, CONFIG_BACKUP_CHECKSUM_PATH);
   std::unique_ptr<config_t> config_paired = config_new_clone(*config);
   btif_config_remove_unpaired(config_paired.get());
   config_save(*config_paired, CONFIG_FILE_PATH);
+  // Save hash
+  std::string current_hash = hash_file(CONFIG_FILE_PATH);
+  if (!current_hash.empty()) {
+    write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
+  }
 }
 
 static void btif_config_remove_unpaired(config_t* conf) {
@@ -576,5 +637,65 @@
 static void delete_config_files(void) {
   remove(CONFIG_FILE_PATH);
   remove(CONFIG_BACKUP_PATH);
+  remove(CONFIG_FILE_CHECKSUM_PATH);
+  remove(CONFIG_BACKUP_CHECKSUM_PATH);
   osi_property_set("persist.bluetooth.factoryreset", "false");
 }
+
+static std::string hash_file(const char* filename) {
+  if (!use_key_attestation()) {
+    LOG(INFO) << __func__ << ": Disabled for multi-user";
+    return DISABLED;
+  }
+  FILE* fp = fopen(filename, "rb");
+  if (!fp) {
+    LOG(ERROR) << __func__ << ": unable to open config file: '" << filename
+               << "': " << strerror(errno);
+    return "";
+  }
+  uint8_t hash[SHA256_DIGEST_LENGTH];
+  SHA256_CTX sha256;
+  SHA256_Init(&sha256);
+  std::array<std::byte, kBufferSize> buffer;
+  int bytes_read = 0;
+  while ((bytes_read = fread(buffer.data(), 1, buffer.size(), fp))) {
+    SHA256_Update(&sha256, buffer.data(), bytes_read);
+  }
+  SHA256_Final(hash, &sha256);
+  std::stringstream ss;
+  for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+    ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
+  }
+  fclose(fp);
+  return ss.str();
+}
+
+static std::string read_checksum_file(const char* checksum_filename) {
+  if (!use_key_attestation()) {
+    LOG(INFO) << __func__ << ": Disabled for multi-user";
+    return DISABLED;
+  }
+  std::string encrypted_hash = checksum_read(checksum_filename);
+  if (encrypted_hash.empty()) {
+    LOG(INFO) << __func__ << ": read empty hash.";
+    return "";
+  }
+  return btif_keystore.Decrypt(encrypted_hash);
+}
+
+static void write_checksum_file(const char* checksum_filename,
+                                const std::string& hash) {
+  if (!use_key_attestation()) {
+    LOG(INFO) << __func__
+              << ": Disabled for multi-user, since config changed removing "
+                 "checksums.";
+    remove(CONFIG_FILE_CHECKSUM_PATH);
+    remove(CONFIG_BACKUP_CHECKSUM_PATH);
+    return;
+  }
+  std::string encrypted_checksum = btif_keystore.Encrypt(hash, 0);
+  CHECK(!encrypted_checksum.empty())
+      << __func__ << ": Failed encrypting checksum";
+  CHECK(checksum_save(encrypted_checksum, checksum_filename))
+      << __func__ << ": Failed to save checksum!";
+}
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 683834a..a450c27 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -260,6 +260,11 @@
   return !memcmp(zero, data, sizeof(zero));
 }
 
+static bool is_bonding_or_sdp() {
+  return pairing_cb.state == BT_BOND_STATE_BONDING ||
+         (pairing_cb.state == BT_BOND_STATE_BONDED && pairing_cb.sdp_attempts);
+}
+
 static void btif_dm_data_copy(uint16_t event, char* dst, char* src) {
   tBTA_DM_SEC* dst_dm_sec = (tBTA_DM_SEC*)dst;
   tBTA_DM_SEC* src_dm_sec = (tBTA_DM_SEC*)src;
@@ -486,8 +491,6 @@
                                bt_bond_state_t state) {
   btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state);
 
-  // Send bonding state only once - based on outgoing/incoming we may receive
-  // duplicates
   if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING)) {
     // Cross key pairing so send callback for static address
     if (!pairing_cb.static_bdaddr.IsEmpty()) {
@@ -505,14 +508,18 @@
   auto tmp = bd_addr;
   HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);
 
-  if (state == BT_BOND_STATE_BONDING) {
+  int dev_type;
+  if (!btif_get_device_type(bd_addr, &dev_type)) {
+    dev_type = BT_DEVICE_TYPE_BREDR;
+  }
+
+  if (state == BT_BOND_STATE_BONDING ||
+      (state == BT_BOND_STATE_BONDED && pairing_cb.sdp_attempts > 0)) {
+    // Save state for the device is bonding or SDP.
     pairing_cb.state = state;
     pairing_cb.bd_addr = bd_addr;
   } else {
-    if (!pairing_cb.sdp_attempts)
-      memset(&pairing_cb, 0, sizeof(pairing_cb));
-    else
-      BTIF_TRACE_DEBUG("%s: BR-EDR service discovery active", __func__);
+    pairing_cb = {};
   }
 }
 
@@ -1110,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;
@@ -1138,6 +1144,17 @@
 
         /* Trigger SDP on the device */
         pairing_cb.sdp_attempts = 1;
+
+        if (is_crosskey) {
+          // If bonding occurred due to cross-key pairing, send bonding callback
+          // for static address now
+          LOG_INFO(LOG_TAG,
+                   "%s: send bonding state update for static address %s",
+                   __func__, bd_addr.ToString().c_str());
+          bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
+        }
+        bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDED);
+
         btif_dm_get_remote_services(bd_addr);
       }
     }
@@ -1170,6 +1187,7 @@
       case HCI_ERR_AUTH_FAILURE:
       case HCI_ERR_KEY_MISSING:
         btif_storage_remove_bonded_device(&bd_addr);
+        [[fallthrough]];
       case HCI_ERR_HOST_REJECT_SECURITY:
       case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
       case HCI_ERR_UNIT_KEY_USED:
@@ -1395,9 +1413,9 @@
 
       BTIF_TRACE_DEBUG("%s:(result=0x%x, services 0x%x)", __func__,
                        p_data->disc_res.result, p_data->disc_res.services);
-      if ((p_data->disc_res.result != BTA_SUCCESS) &&
-          (pairing_cb.state == BT_BOND_STATE_BONDING) &&
-          (pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING)) {
+      if (p_data->disc_res.result != BTA_SUCCESS &&
+          pairing_cb.state == BT_BOND_STATE_BONDED &&
+          pairing_cb.sdp_attempts < BTIF_DM_MAX_SDP_ATTEMPTS_AFTER_PAIRING) {
         if (pairing_cb.sdp_attempts) {
           BTIF_TRACE_WARNING("%s: SDP failed after bonding re-attempting",
                              __func__);
@@ -1424,21 +1442,36 @@
       /* onUuidChanged requires getBondedDevices to be populated.
       ** bond_state_changed needs to be sent prior to remote_device_property
       */
-      if ((pairing_cb.state == BT_BOND_STATE_BONDING) &&
+      if (pairing_cb.state == BT_BOND_STATE_BONDED && pairing_cb.sdp_attempts &&
           (p_data->disc_res.bd_addr == pairing_cb.bd_addr ||
-           p_data->disc_res.bd_addr == pairing_cb.static_bdaddr) &&
-          pairing_cb.sdp_attempts > 0) {
-        BTIF_TRACE_DEBUG(
-            "%s Remote Service SDP done. Call bond_state_changed_cb BONDED",
-            __func__);
+           p_data->disc_res.bd_addr == pairing_cb.static_bdaddr)) {
+        LOG_INFO(LOG_TAG, "%s: SDP search done for %s", __func__,
+                 bd_addr.ToString().c_str());
         pairing_cb.sdp_attempts = 0;
 
-        // If bonding occured due to cross-key pairing, send bonding callback
-        // for static address now
-        if (p_data->disc_res.bd_addr == pairing_cb.static_bdaddr)
-          bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDING);
+        // Both SDP and bonding are done, clear pairing control block in case
+        // it is not already cleared
+        pairing_cb = {};
 
-        bond_state_changed(BT_STATUS_SUCCESS, bd_addr, BT_BOND_STATE_BONDED);
+        // Send one empty UUID to Java to unblock pairing intent when SDP failed
+        // or no UUID is discovered
+        if (p_data->disc_res.result != BTA_SUCCESS ||
+            p_data->disc_res.num_uuids == 0) {
+          LOG_INFO(LOG_TAG,
+                   "%s: SDP failed, send empty UUID to unblock bonding %s",
+                   __func__, bd_addr.ToString().c_str());
+          bt_property_t prop;
+          Uuid uuid = {};
+
+          prop.type = BT_PROPERTY_UUIDS;
+          prop.val = &uuid;
+          prop.len = Uuid::kNumBytes128;
+
+          /* Send the event to the BTIF */
+          HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb,
+                    BT_STATUS_SUCCESS, &bd_addr, 1, &prop);
+          break;
+        }
       }
 
       if (p_data->disc_res.num_uuids != 0) {
@@ -1634,7 +1667,7 @@
       break;
 
     case BTA_DM_BOND_CANCEL_CMPL_EVT:
-      if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+      if (is_bonding_or_sdp()) {
         bd_addr = pairing_cb.bd_addr;
         btm_set_bond_type_dev(pairing_cb.bd_addr, BOND_TYPE_UNKNOWN);
         bond_state_changed((bt_status_t)p_data->bond_cancel_cmpl.result,
@@ -2274,7 +2307,7 @@
   **  1. Restore scan modes
   **  2. special handling for HID devices
   */
-  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+  if (is_bonding_or_sdp()) {
     if (pairing_cb.is_ssp) {
       if (pairing_cb.is_le_only) {
         BTA_DmBleSecurityGrant(*bd_addr, BTA_DM_SEC_PAIR_NOT_SPT);
@@ -2486,7 +2519,7 @@
 
 /*******************************************************************************
  *
- * Function         btif_dm_get_remote_services_transport
+ * Function         btif_dm_get_remote_services_by_transport
  *
  * Description      Start SDP to get remote services by transport
  *
@@ -2850,7 +2883,7 @@
       btif_storage_remove_bonded_device(&bdaddr);
       state = BT_BOND_STATE_NONE;
     } else {
-      btif_dm_save_ble_bonding_keys();
+      btif_dm_save_ble_bonding_keys(bdaddr);
       btif_dm_get_remote_services_by_transport(&bd_addr, GATT_TRANSPORT_LE);
     }
   } else {
@@ -2885,6 +2918,10 @@
         break;
     }
   }
+  if (state == BT_BOND_STATE_BONDED && bd_addr != pairing_cb.static_bdaddr) {
+    // Report RPA bonding state to Java in crosskey paring
+    bond_state_changed(status, bd_addr, BT_BOND_STATE_BONDING);
+  }
   bond_state_changed(status, bd_addr, state);
 }
 
@@ -2927,11 +2964,9 @@
   BTIF_TRACE_DEBUG("%s  *p_key_mask=0x%02x", __func__, *p_key_mask);
 }
 
-void btif_dm_save_ble_bonding_keys(void) {
+void btif_dm_save_ble_bonding_keys(RawAddress& bd_addr) {
   BTIF_TRACE_DEBUG("%s", __func__);
 
-  RawAddress bd_addr = pairing_cb.bd_addr;
-
   if (pairing_cb.ble.is_penc_key_rcvd) {
     btif_storage_add_ble_bonding_key(
         &bd_addr, (uint8_t*)&pairing_cb.ble.penc_key, BTIF_DM_LE_KEY_PENC,
@@ -3191,7 +3226,7 @@
 
 void btif_dm_on_disable() {
   /* cancel any pending pairing requests */
-  if (pairing_cb.state == BT_BOND_STATE_BONDING) {
+  if (is_bonding_or_sdp()) {
     BTIF_TRACE_DEBUG("%s: Cancel pending pairing request", __func__);
     btif_dm_cancel_bond(&pairing_cb.bd_addr);
   }
diff --git a/btif/src/btif_hf.cc b/btif/src/btif_hf.cc
index e0e9515..04ad011 100644
--- a/btif/src/btif_hf.cc
+++ b/btif/src/btif_hf.cc
@@ -412,7 +412,7 @@
     case BTA_AG_AT_BLDN_EVT:
     case BTA_AG_AT_D_EVT:
       bt_hf_callbacks->DialCallCallback(
-          (event == BTA_AG_AT_D_EVT) ? p_data->val.str : nullptr,
+          (event == BTA_AG_AT_D_EVT) ? p_data->val.str : (char*)"",
           &btif_hf_cb[idx].connected_bda);
       break;
 
diff --git a/btif/src/btif_hf_client.cc b/btif/src/btif_hf_client.cc
index e40975e..e7181e9 100644
--- a/btif/src/btif_hf_client.cc
+++ b/btif/src/btif_hf_client.cc
@@ -747,7 +747,7 @@
 }
 
 static const bthf_client_interface_t bthfClientInterface = {
-    sizeof(bthf_client_interface_t),
+    .size = sizeof(bthf_client_interface_t),
     .init = init,
     .connect = connect,
     .disconnect = disconnect,
@@ -949,7 +949,7 @@
                 (bthf_client_call_state_t)p_data->clcc.status,
                 p_data->clcc.mpty ? BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
                                   : BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE,
-                p_data->clcc.number_present ? p_data->clcc.number : NULL);
+                p_data->clcc.number_present ? p_data->clcc.number : "");
       break;
 
     case BTA_HF_CLIENT_CNUM_EVT:
diff --git a/btif/src/btif_keystore.cc b/btif/src/btif_keystore.cc
new file mode 100644
index 0000000..0af03e1
--- /dev/null
+++ b/btif/src/btif_keystore.cc
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ *  Copyright 2019 Google, Inc.
+ *
+ *  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 "btif_keystore.h"
+
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
+#include <base/strings/string_util.h>
+#include <base/strings/utf_string_conversions.h>
+#include <sys/stat.h>
+
+using namespace keystore;
+using namespace bluetooth;
+
+constexpr char kKeyStore[] = "AndroidKeystore";
+
+namespace bluetooth {
+
+BtifKeystore::BtifKeystore(keystore::KeystoreClient* keystore_client)
+    : keystore_client_(keystore_client) {}
+
+std::string BtifKeystore::Encrypt(const std::string& data, int32_t flags) {
+  std::lock_guard<std::mutex> lock(api_mutex_);
+  std::string output;
+  if (data.empty()) {
+    LOG(ERROR) << __func__ << ": empty data";
+    return output;
+  }
+  if (!keystore_client_->doesKeyExist(kKeyStore)) {
+    auto gen_result = GenerateKey(kKeyStore, 0, false);
+    if (!gen_result.isOk()) {
+      LOG(FATAL) << "EncryptWithAuthentication Failed: generateKey response="
+                 << gen_result;
+      return output;
+    }
+  }
+  if (!keystore_client_->encryptWithAuthentication(kKeyStore, data, flags,
+                                                   &output)) {
+    LOG(FATAL) << "EncryptWithAuthentication failed.";
+    return output;
+  }
+  return output;
+}
+
+std::string BtifKeystore::Decrypt(const std::string& input) {
+  std::lock_guard<std::mutex> lock(api_mutex_);
+  if (input.empty()) {
+    LOG(ERROR) << __func__ << ": empty input data";
+    return "";
+  }
+  std::string output;
+  if (!keystore_client_->decryptWithAuthentication(kKeyStore, input, &output)) {
+    LOG(FATAL) << "DecryptWithAuthentication failed.\n";
+  }
+  return output;
+}
+
+// Note: auth_bound keys created with this tool will not be usable.
+KeyStoreNativeReturnCode BtifKeystore::GenerateKey(const std::string& name,
+                                                   int32_t flags,
+                                                   bool auth_bound) {
+  AuthorizationSetBuilder params;
+  params.RsaSigningKey(2048, 65537)
+      .Digest(Digest::SHA_2_224)
+      .Digest(Digest::SHA_2_256)
+      .Digest(Digest::SHA_2_384)
+      .Digest(Digest::SHA_2_512)
+      .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+      .Padding(PaddingMode::RSA_PSS);
+  if (auth_bound) {
+    // Gatekeeper normally generates the secure user id.
+    // Using zero allows the key to be created, but it will not be usuable.
+    params.Authorization(TAG_USER_SECURE_ID, 0);
+  } else {
+    params.Authorization(TAG_NO_AUTH_REQUIRED);
+  }
+  AuthorizationSet hardware_enforced_characteristics;
+  AuthorizationSet software_enforced_characteristics;
+  return keystore_client_->generateKey(name, params, flags,
+                                       &hardware_enforced_characteristics,
+                                       &software_enforced_characteristics);
+}
+
+bool BtifKeystore::DoesKeyExist() {
+  return keystore_client_->doesKeyExist(kKeyStore);
+}
+
+}  // namespace bluetooth
diff --git a/btif/src/btif_profile_queue.cc b/btif/src/btif_profile_queue.cc
index 41275f1..900a6af 100644
--- a/btif/src/btif_profile_queue.cc
+++ b/btif/src/btif_profile_queue.cc
@@ -195,7 +195,14 @@
 
   LOG_INFO(LOG_TAG, "%s: executing connection request: %s", __func__,
            head.ToString().c_str());
-  return head.connect();
+  bt_status_t b_status = head.connect();
+  if (b_status != BT_STATUS_SUCCESS) {
+    LOG_INFO(LOG_TAG,
+             "%s: connect %s failed, advance to next scheduled connection.",
+             __func__, head.ToString().c_str());
+    btif_queue_advance();
+  }
+  return b_status;
 }
 
 /*******************************************************************************
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 6935651..d8ea94c 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -2535,9 +2535,9 @@
     BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
                      __func__, volume);
 
-    tAVRC_COMMAND avrc_cmd = {.volume = {.opcode = AVRC_OP_VENDOR,
-                                         .pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME,
+    tAVRC_COMMAND avrc_cmd = {.volume = {.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME,
                                          .status = AVRC_STS_NO_ERROR,
+                                         .opcode = AVRC_OP_VENDOR,
                                          .volume = volume}};
 
     BT_HDR* p_msg = NULL;
@@ -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;
 
@@ -3811,6 +3810,10 @@
   if (p_rsp->status == AVRC_STS_NO_ERROR) {
     do_in_jni_thread(
         FROM_HERE,
+        base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, p_dev->rc_addr,
+                   (btrc_play_status_t)p_rsp->play_status));
+    do_in_jni_thread(
+        FROM_HERE,
         base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb,
                    p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos));
   } else {
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index b6ffcda..e203d2f 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -889,9 +889,8 @@
     tBTA_LE_KEY_VALUE key;
     memset(&key, 0, sizeof(key));
 
-    if (btif_storage_get_ble_bonding_key(
-            &bd_addr, BTIF_DM_LE_KEY_PENC, (uint8_t*)&key,
-            sizeof(tBTM_LE_PENC_KEYS)) == BT_STATUS_SUCCESS) {
+    if (btif_storage_get_ble_bonding_key(&bd_addr, BTIF_DM_LE_KEY_PENC, (uint8_t*)&key, sizeof(tBTM_LE_PENC_KEYS)) ==
+        BT_STATUS_SUCCESS) {
       if (is_sample_ltk(key.penc_key.ltk)) {
         bad_ltk.push_back(bd_addr);
       }
@@ -900,8 +899,7 @@
 
   for (RawAddress address : bad_ltk) {
     android_errorWriteLog(0x534e4554, "128437297");
-    LOG(ERROR) << __func__
-               << ": removing bond to device using test TLK: " << address;
+    LOG(ERROR) << __func__ << ": removing bond to device using test TLK: " << address;
 
     btif_storage_remove_bonded_device(&address);
   }
@@ -1121,6 +1119,7 @@
       break;
     case BTIF_DM_LE_KEY_LID:
       name = "LE_KEY_LID";
+      break;
     default:
       return BT_STATUS_FAIL;
   }
diff --git a/btif/test/btif_keystore_test.cc b/btif/test/btif_keystore_test.cc
new file mode 100644
index 0000000..4cabbad
--- /dev/null
+++ b/btif/test/btif_keystore_test.cc
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ *  Copyright 2019 Google, Inc.
+ *
+ *  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 <base/logging.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <fstream>
+
+#include "btif/include/btif_keystore.h"
+
+using namespace bluetooth;
+
+class BtifKeystoreTest : public ::testing::Test {
+ protected:
+  std::unique_ptr<BtifKeystore> btif_keystore_;
+  void SetUp() override {
+    android::ProcessState::self()->startThreadPool();
+    btif_keystore_ =
+        std::make_unique<BtifKeystore>(static_cast<keystore::KeystoreClient*>(
+            new keystore::KeystoreClientImpl));
+  };
+  void TearDown() override { btif_keystore_ = nullptr; };
+};
+
+TEST_F(BtifKeystoreTest, test_encrypt_decrypt) {
+  std::string hash = "test";
+
+  std::string encrypted_hash = btif_keystore_->Encrypt(hash, 0);
+  std::string decrypted_hash = btif_keystore_->Decrypt(encrypted_hash);
+
+  EXPECT_FALSE(encrypted_hash.empty());
+  EXPECT_EQ(hash, decrypted_hash);
+}
+
+TEST_F(BtifKeystoreTest, test_encrypt_empty_hash) {
+  std::string hash = "";
+
+  std::string encrypted_hash = btif_keystore_->Encrypt(hash, 0);
+
+  EXPECT_TRUE(encrypted_hash.empty());
+}
+
+TEST_F(BtifKeystoreTest, test_decrypt_empty_hash) {
+  std::string hash = "";
+
+  std::string decrypted_hash = btif_keystore_->Decrypt(hash);
+
+  EXPECT_TRUE(decrypted_hash.empty());
+}
diff --git a/btif/test/btif_profile_queue_test.cc b/btif/test/btif_profile_queue_test.cc
index 486959b..af0255b 100644
--- a/btif/test/btif_profile_queue_test.cc
+++ b/btif/test/btif_profile_queue_test.cc
@@ -97,6 +97,49 @@
   EXPECT_EQ(sResult, UUID1_ADDR1);
 }
 
+static bt_status_t test_connect_cb_fail(RawAddress* bda, uint16_t uuid) {
+  sResult = UNKNOWN;
+  if (*bda == BtifProfileQueueTest::kTestAddr1) {
+    if (uuid == BtifProfileQueueTest::kTestUuid1) {
+      sResult = UUID1_ADDR1;
+    } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+      sResult = UUID2_ADDR1;
+    }
+  } else if (*bda == BtifProfileQueueTest::kTestAddr2) {
+    if (uuid == BtifProfileQueueTest::kTestUuid1) {
+      sResult = UUID1_ADDR2;
+    } else if (uuid == BtifProfileQueueTest::kTestUuid2) {
+      sResult = UUID2_ADDR2;
+    }
+  }
+  return BT_STATUS_BUSY;
+}
+
+TEST_F(BtifProfileQueueTest, test_connect_fail_still_can_advance_the_queue) {
+  sResult = NOT_SET;
+  // First connect-message for UUID1-ADDR1 is executed, but does not be removed
+  // from connect-queue yet.
+  btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
+  EXPECT_EQ(sResult, UUID1_ADDR1);
+  sResult = NOT_SET;
+  // Second connect-message for UUID2-ADDR1 be pushed into connect-queue, but is
+  // not executed
+  btif_queue_connect(kTestUuid2, &kTestAddr1, test_connect_cb_fail);
+  EXPECT_EQ(sResult, NOT_SET);
+  // Third connect-message for UUID1-ADDR2 be pushed into connect-queue, but is
+  // not executed
+  btif_queue_connect(kTestUuid1, &kTestAddr2, test_connect_cb_fail);
+  EXPECT_EQ(sResult, NOT_SET);
+  // Fourth connect-message for UUID2-ADDR2 be pushed into connect-queue, but is
+  // not executed
+  btif_queue_connect(kTestUuid2, &kTestAddr2, test_connect_cb_fail);
+  EXPECT_EQ(sResult, NOT_SET);
+  // removed First connect-message from connect-queue, check it can advance to
+  // subsequent connect-message.
+  btif_queue_advance();
+  EXPECT_EQ(sResult, UUID2_ADDR2);
+}
+
 TEST_F(BtifProfileQueueTest, test_connect_same_uuid_do_not_repeat) {
   sResult = NOT_SET;
   btif_queue_connect(kTestUuid1, &kTestAddr1, test_connect_cb);
diff --git a/build/Android.bp b/build/Android.bp
index 768d6ec..32c0f31 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -29,9 +29,10 @@
     },
 }
 
+// Fuzzable defaults are the subset of defaults that are used in fuzzing, which
+// requires no shared libraries, and no explicit sanitization.
 fluoride_defaults {
-    name: "fluoride_types_defaults",
-    defaults: ["libchrome_support_defaults"],
+    name: "fluoride_types_defaults_fuzzable",
     cflags: [
         "-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
         "-fvisibility=hidden",
@@ -54,15 +55,22 @@
 }
 
 fluoride_defaults {
-    name: "fluoride_defaults",
+    name: "fluoride_types_defaults",
+    defaults: [
+        "fluoride_types_defaults_fuzzable",
+        "libchrome_support_defaults"
+    ],
+}
+
+fluoride_defaults {
+    name: "fluoride_defaults_fuzzable",
     target: {
         android: {
             test_config_template: ":BluetoothTestConfigTemplate",
         },
     },
-    defaults: ["fluoride_types_defaults"],
+    defaults: ["fluoride_types_defaults_fuzzable"],
     header_libs: ["libbluetooth_headers"],
-    shared_libs: ["libstatslog"],
     static_libs: [
         "libbluetooth-types",
         "libbt-platform-protos-lite",
@@ -73,6 +81,15 @@
     },
 }
 
+fluoride_defaults {
+    name: "fluoride_defaults",
+    defaults: ["fluoride_defaults_fuzzable", "fluoride_types_defaults"],
+    shared_libs: ["libstatslog"],
+    sanitize: {
+        misc_undefined: ["bounds"],
+    },
+}
+
 // Enables code coverage for a set of source files. Must be combined with
 // "clang_coverage_bin" in order to work. See //test/gen_coverage.py for more information
 // on generating code coverage.
@@ -83,10 +100,6 @@
             clang_cflags: [
                 "-fprofile-instr-generate",
                 "-fcoverage-mapping",
-
-                // New pass manager does not work with -fprofile-instr-generate yet.
-                // http://b/131132095
-                "-fno-experimental-new-pass-manager",
             ],
         },
     },
@@ -105,10 +118,6 @@
             ldflags: [
                 "-fprofile-instr-generate",
                 "-fcoverage-mapping",
-
-                // New pass manager does not work with -fprofile-instr-generate yet.
-                // http://b/131132095
-                "-fno-experimental-new-pass-manager",
             ],
         },
     },
diff --git a/common/scoped_scs_exit.h b/common/scoped_scs_exit.h
deleted file mode 100644
index ad4a8d6..0000000
--- a/common/scoped_scs_exit.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2018 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
-
-// Prevent x18 (shadow call stack address) from being clobbered by functions
-// called by a function that declares a variable of this type by temporarily
-// storing the value on the stack. This is used only when calling out to certain
-// vendor libraries.
-struct ScopedSCSExit {
-#ifdef __aarch64__
-    void* scs;
-
-    __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ScopedSCSExit() {
-        __asm__ __volatile__("str x18, [%0]" ::"r"(&scs));
-    }
-
-    __attribute__((always_inline, no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {
-        __asm__ __volatile__("ldr x18, [%0]; str xzr, [%0]" ::"r"(&scs));
-    }
-#else
-    // Silence unused variable warnings in non-SCS builds.
-    __attribute__((no_sanitize("shadow-call-stack"))) ScopedSCSExit() {}
-    __attribute__((no_sanitize("shadow-call-stack"))) ~ScopedSCSExit() {}
-#endif
-};
diff --git a/device/include/controller.h b/device/include/controller.h
index c1fe337..a15f57b 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -89,6 +89,12 @@
 
 } controller_t;
 
+namespace bluetooth {
+namespace legacy {
+const controller_t* controller_get_interface();
+}  // namespace legacy
+}  // namespace bluetooth
+
 const controller_t* controller_get_interface();
 
 const controller_t* controller_get_test_interface(
diff --git a/device/include/interop.h b/device/include/interop.h
index a9bf586..d7ca917 100644
--- a/device/include/interop.h
+++ b/device/include/interop.h
@@ -94,6 +94,12 @@
   // Set a very low initial sniff subrating for HID devices that do not
   // set their own sniff interval.
   INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL,
+
+  // Disable remote name requst for some devices.
+  // The public address of these devices are same as the Random address in ADV.
+  // Then will get name by LE_Create_connection, actually fails,
+  // but will block pairing.
+  INTEROP_DISABLE_NAME_REQUEST
 } interop_feature_t;
 
 // Check if a given |addr| matches a known interoperability workaround as
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index 6ea2d83..b4b1b07 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -146,6 +146,10 @@
 
     // AirPods 2 - unacceptably loud volume
     {{{0x9c, 0x64, 0x8b, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+    // for skip name request,
+    // because BR/EDR address and ADV random address are the same
+    {{{0xd4, 0x7a, 0xe2, 0, 0, 0}}, 3, INTEROP_DISABLE_NAME_REQUEST},
 };
 
 typedef struct {
@@ -173,7 +177,8 @@
     // Kenwood KMM-BT518HD - no audio when A2DP codec sample rate is changed
     {"KMM-BT51*HD", 11, INTEROP_DISABLE_AVDTP_RECONFIGURE},
 
-    // Nintendo Switch Pro Controller - does not set sniff interval dynamically.
-    // Requires custom HID report command to change mode.
+    // Nintendo Switch Pro Controller and Joy Con - do not set sniff interval
+    // dynamically. They require custom HID report command to change mode.
     {"Pro Controller", 14, INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL},
+    {"Joy-Con", 7, INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL},
 };
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 34c8afd..537216b 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -27,6 +27,8 @@
 #include "btcore/include/module.h"
 #include "btcore/include/version.h"
 #include "hcimsgs.h"
+#include "main/shim/controller.h"
+#include "main/shim/shim.h"
 #include "osi/include/future.h"
 #include "stack/include/btm_ble_api.h"
 
@@ -582,7 +584,7 @@
     get_local_supported_codecs,
     get_le_all_initiating_phys};
 
-const controller_t* controller_get_interface() {
+const controller_t* bluetooth::legacy::controller_get_interface() {
   static bool loaded = false;
   if (!loaded) {
     loaded = true;
@@ -595,6 +597,14 @@
   return &interface;
 }
 
+const controller_t* controller_get_interface() {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::controller_get_interface();
+  } else {
+    return bluetooth::legacy::controller_get_interface();
+  }
+}
+
 const controller_t* controller_get_test_interface(
     const hci_t* hci_interface,
     const hci_packet_factory_t* packet_factory_interface,
diff --git a/device/src/interop.cc b/device/src/interop.cc
index 76b4a95..9a701b1 100644
--- a/device/src/interop.cc
+++ b/device/src/interop.cc
@@ -131,6 +131,7 @@
     CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
     CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
     CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
+    CASE_RETURN_STR(INTEROP_DISABLE_NAME_REQUEST)
   }
 
   return "UNKNOWN";
diff --git a/embdrv/sbc/decoder/srce/decoder-sbc.c b/embdrv/sbc/decoder/srce/decoder-sbc.c
index 20c5b67..50168b5 100644
--- a/embdrv/sbc/decoder/srce/decoder-sbc.c
+++ b/embdrv/sbc/decoder/srce/decoder-sbc.c
@@ -33,6 +33,12 @@
 
 #define SPECIALIZE_READ_SAMPLES_JOINT
 
+#if __has_attribute(fallthrough)
+#define __fallthrough __attribute__((__fallthrough__))
+#else
+#define __fallthrough
+#endif
+
 /**
  * Scans through a buffer looking for a codec syncword. If the decoder has been
  * set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search
@@ -413,7 +419,7 @@
 
       case SBC_DUAL_CHANNEL:
         frameLen *= 2;
-      /* fall through */
+        __fallthrough;
 
       default:
         if (mode == SBC_MONO) {
diff --git a/gd/Android.bp b/gd/Android.bp
index 62f4950..46108c6 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -28,7 +28,6 @@
         "-DLOG_NDEBUG=1",
         "-DGOOGLE_PROTOBUF_NO_RTTI",
         "-Wno-unused-parameter",
-        "-Wno-implicit-fallthrough",
         "-Wno-unused-result",
     ],
     conlyflags: [
@@ -49,10 +48,6 @@
             clang_cflags: [
                 "-fprofile-instr-generate",
                 "-fcoverage-mapping",
-
-                // New pass manager does not work with -fprofile-instr-generate yet.
-                // http://b/131132095
-                "-fno-experimental-new-pass-manager",
             ],
         },
     },
@@ -71,10 +66,6 @@
             ldflags: [
                 "-fprofile-instr-generate",
                 "-fcoverage-mapping",
-
-                // New pass manager does not work with -fprofile-instr-generate yet.
-                // http://b/131132095
-                "-fno-experimental-new-pass-manager",
             ],
         },
     },
@@ -104,9 +95,7 @@
             ],
             shared_libs: [
                 "android.hardware.bluetooth@1.0",
-                "libhwbinder",
                 "libhidlbase",
-                "libhidltransport",
                 "libutils",
             ],
         },
@@ -119,8 +108,10 @@
         ":BluetoothHalSources",
         ":BluetoothHciSources",
         ":BluetoothL2capSources",
+        ":BluetoothNeighborSources",
         ":BluetoothPacketSources",
-        ":BluetoothSmpSources",
+        ":BluetoothShimSources",
+        ":BluetoothSecuritySources",
     ],
     generated_headers: [
         "BluetoothGeneratedPackets_h",
@@ -131,7 +122,7 @@
 }
 
 cc_binary {
-    name: "stack_with_facade",
+    name: "bluetooth_stack_with_facade",
     defaults: [
         "gd_defaults",
     ],
@@ -139,6 +130,7 @@
     srcs: [
         "facade/facade_main.cc",
         "facade/grpc_root_server.cc",
+        "facade/read_only_property_server.cc",
         "grpc/grpc_module.cc",
         ":BluetoothFacade_hci_hal",
         ":BluetoothFacade_hci_layer",
@@ -163,9 +155,7 @@
         android: {
             shared_libs: [
                 "android.hardware.bluetooth@1.0",
-                "libhwbinder",
                 "libhidlbase",
-                "libhidltransport",
                 "libutils",
             ],
         },
@@ -184,6 +174,7 @@
     srcs: [
         "cert/cert_main.cc",
         "cert/grpc_root_server.cc",
+        "cert/read_only_property_server.cc",
         "grpc/grpc_module.cc",
         ":BluetoothCertSource_hci_hal",
         ":BluetoothCertSource_hci_layer",
@@ -208,9 +199,7 @@
         android: {
             shared_libs: [
                 "android.hardware.bluetooth@1.0",
-                "libhwbinder",
                 "libhidlbase",
-                "libhidltransport",
                 "libutils",
             ],
         },
@@ -245,9 +234,7 @@
             ],
             shared_libs: [
                 "android.hardware.bluetooth@1.0",
-                "libhwbinder",
                 "libhidlbase",
-                "libhidltransport",
                 "libutils",
             ],
         },
@@ -259,8 +246,10 @@
         ":BluetoothCryptoToolboxTestSources",
         ":BluetoothHciTestSources",
         ":BluetoothL2capTestSources",
+        ":BluetoothNeighborTestSources",
         ":BluetoothPacketTestSources",
-        ":BluetoothSmpTestSources",
+        ":BluetoothSecurityTestSources",
+        ":BluetoothShimTestSources",
     ],
     generated_headers: [
         "BluetoothGeneratedPackets_h",
@@ -298,6 +287,35 @@
     },
 }
 
+cc_fuzz {
+  name: "bluetooth_gd_fuzz_test",
+  defaults: ["gd_defaults"],
+  srcs: [
+    "fuzz_test.cc",
+    ":BluetoothHciFuzzTestSources",
+    ":BluetoothL2capFuzzTestSources",
+  ],
+  static_libs: [
+    "libbluetooth_gd",
+    "libchrome",
+    "libgmock",
+    "libgtest",
+  ],
+  host_supported: true,
+  generated_headers: [
+    "BluetoothGeneratedPackets_h",
+  ],
+  target: {
+    android: {
+        shared_libs: [
+            "android.hardware.bluetooth@1.0",
+            "libhidlbase",
+            "libutils",
+        ],
+    },
+  },
+}
+
 cc_benchmark {
     name: "bluetooth_benchmark_gd",
     defaults: ["gd_defaults"],
@@ -314,6 +332,14 @@
     ],
 }
 
+filegroup {
+    name: "BluetoothHciClassSources",
+    srcs: [
+        "hci/address.cc",
+        "hci/class_of_device.cc",
+        ],
+}
+
 genrule {
     name: "BluetoothGeneratedPackets_h",
     tools: [
@@ -323,10 +349,45 @@
     srcs: [
         "hci/hci_packets.pdl",
         "l2cap/l2cap_packets.pdl",
+        "security/smp_packets.pdl",
     ],
     out: [
         "hci/hci_packets.h",
         "l2cap/l2cap_packets.h",
+        "security/smp_packets.h",
+    ],
+}
+
+genrule {
+    name: "BluetoothGeneratedPackets_python3_cc",
+    tools: [
+        "bluetooth_packetgen",
+    ],
+    cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) --num_shards=5 $(in)",
+    srcs: [
+        "hci/hci_packets.pdl",
+        "l2cap/l2cap_packets.pdl",
+        "security/smp_packets.pdl",
+    ],
+    out: [
+        "hci/hci_packets_python3.cc",
+        "hci/hci_packets_python3_shard_0.cc",
+        "hci/hci_packets_python3_shard_1.cc",
+        "hci/hci_packets_python3_shard_2.cc",
+        "hci/hci_packets_python3_shard_3.cc",
+        "hci/hci_packets_python3_shard_4.cc",
+        "l2cap/l2cap_packets_python3.cc",
+        "l2cap/l2cap_packets_python3_shard_0.cc",
+        "l2cap/l2cap_packets_python3_shard_1.cc",
+        "l2cap/l2cap_packets_python3_shard_2.cc",
+        "l2cap/l2cap_packets_python3_shard_3.cc",
+        "l2cap/l2cap_packets_python3_shard_4.cc",
+        "security/smp_packets_python3.cc",
+        "security/smp_packets_python3_shard_0.cc",
+        "security/smp_packets_python3_shard_1.cc",
+        "security/smp_packets_python3_shard_2.cc",
+        "security/smp_packets_python3_shard_3.cc",
+        "security/smp_packets_python3_shard_4.cc",
     ],
 }
 
@@ -337,7 +398,7 @@
         "facade/rootservice.proto",
         "hal/facade.proto",
         "hci/facade.proto",
-        "l2cap/facade.proto",
+        "l2cap/classic/facade.proto",
     ],
 }
 
@@ -360,8 +421,8 @@
         "hal/facade.pb.h",
         "hci/facade.grpc.pb.h",
         "hci/facade.pb.h",
-        "l2cap/facade.grpc.pb.h",
-        "l2cap/facade.pb.h",
+        "l2cap/classic/facade.grpc.pb.h",
+        "l2cap/classic/facade.pb.h",
     ],
 }
 
@@ -384,8 +445,8 @@
         "hal/facade.pb.cc",
         "hci/facade.grpc.pb.cc",
         "hci/facade.pb.cc",
-        "l2cap/facade.grpc.pb.cc",
-        "l2cap/facade.pb.cc",
+        "l2cap/classic/facade.grpc.pb.cc",
+        "l2cap/classic/facade.pb.cc",
     ],
 }
 
@@ -401,8 +462,8 @@
         "touch $(genDir)/hal/cert/__init__.py; " +
         "touch $(genDir)/hci/__init__.py; " +
         "touch $(genDir)/hci/cert/__init__.py; " +
-        "touch $(genDir)/l2cap/__init__.py; " +
-        "touch $(genDir)/l2cap/cert/__init__.py; ",
+        "touch $(genDir)/l2cap/classic/__init__.py; " +
+        "touch $(genDir)/l2cap/classic/cert/__init__.py; ",
     srcs: [
         ":BluetoothFacadeProto",
         ":BluetoothCertStackProto",
@@ -421,18 +482,18 @@
         "hci/__init__.py",
         "hci/facade_pb2_grpc.py",
         "hci/facade_pb2.py",
-        "l2cap/__init__.py",
-        "l2cap/facade_pb2_grpc.py",
-        "l2cap/facade_pb2.py",
+        "l2cap/classic/__init__.py",
+        "l2cap/classic/facade_pb2_grpc.py",
+        "l2cap/classic/facade_pb2.py",
         "hal/cert/__init__.py",
         "hal/cert/api_pb2_grpc.py",
         "hal/cert/api_pb2.py",
         "hci/cert/__init__.py",
         "hci/cert/api_pb2_grpc.py",
         "hci/cert/api_pb2.py",
-        "l2cap/cert/__init__.py",
-        "l2cap/cert/api_pb2_grpc.py",
-        "l2cap/cert/api_pb2.py",
+        "l2cap/classic/cert/__init__.py",
+        "l2cap/classic/cert/api_pb2_grpc.py",
+        "l2cap/classic/cert/api_pb2.py",
     ],
 }
 
@@ -442,7 +503,7 @@
         "cert/rootservice.proto",
         "hal/cert/api.proto",
         "hci/cert/api.proto",
-        "l2cap/cert/api.proto",
+        "l2cap/classic/cert/api.proto",
     ],
 }
 
@@ -466,8 +527,8 @@
         "hal/cert/api.pb.h",
         "hci/cert/api.grpc.pb.h",
         "hci/cert/api.pb.h",
-        "l2cap/cert/api.grpc.pb.h",
-        "l2cap/cert/api.pb.h",
+        "l2cap/classic/cert/api.grpc.pb.h",
+        "l2cap/classic/cert/api.pb.h",
     ],
 }
 
@@ -491,7 +552,95 @@
         "hal/cert/api.pb.cc",
         "hci/cert/api.grpc.pb.cc",
         "hci/cert/api.pb.cc",
-        "l2cap/cert/api.grpc.pb.cc",
-        "l2cap/cert/api.pb.cc",
+        "l2cap/classic/cert/api.grpc.pb.cc",
+        "l2cap/classic/cert/api.pb.cc",
     ],
 }
+
+cc_defaults {
+  name: "bluetooth_py3_native_extension_defaults",
+  include_dirs: [
+    "external/python/cpython3/Include",
+  ],
+  target: {
+      android: {
+          include_dirs: ["external/python/cpython3/android/bionic/pyconfig"],
+      },
+      android_arm: {
+          cflags: ["-DSOABI=\"cpython-38android-arm-android-bionic\""],
+          suffix: ".cpython-38android-arm-android-bionic",
+      },
+      android_arm64: {
+          cflags: ["-DSOABI=\"cpython-38android-arm64-android-bionic\""],
+          suffix: ".cpython-38android-arm64-android-bionic",
+      },
+      android_x86: {
+          cflags: ["-DSOABI=\"cpython-38android-x86-android-bionic\""],
+          suffix: ".cpython-38android-x86-android-bionic",
+      },
+      android_x86_64: {
+          cflags: ["-DSOABI=\"cpython-38android-x86_64-android-bionic\""],
+          suffix: ".cpython-38android-x86_64-android-bionic",
+      },
+      // Regenerate include dirs with android_regen.sh
+      darwin_x86_64: {
+          include_dirs: ["external/python/cpython3/android/darwin_x86_64/pyconfig"],
+          cflags: [
+              "-Wno-deprecated-declarations",
+              "-Wno-pointer-arith",
+              "-DSOABI=\"cpython-38android-x86_64-darwin\"",
+          ],
+          suffix: ".cpython-38android-x86_64-darwin",
+      },
+      linux_bionic: {
+          // NB linux_bionic is a 'host' architecture but it uses the bionic libc like 'android'
+          // targets so use the android pyconfig.
+          include_dirs: ["external/python/cpython3/android/bionic/pyconfig"],
+          cflags: ["-DSOABI=\"cpython-38android-x86_64-linux-bionic\""],
+          suffix: ".cpython-38android-x86_64-linux-bionic",
+      },
+      linux_glibc_x86: {
+          enabled: false,
+      },
+      linux_glibc_x86_64: {
+          include_dirs: ["external/python/cpython3/android/linux_x86_64/pyconfig"],
+          cflags: ["-DSOABI=\"cpython-38android-x86_64-linux-gnu\""],
+          // Commenting out the Linux suffix so that cpython-38-x86_64-linux-gnu
+          // Python 3.8 can also import the untagged .so library per PEP 3149
+          // Keep this change until Android py3-cmd can run ACTS, gRPC and can
+          // Export Python native symbols such as PyType_Type
+          // suffix: ".cpython-38android-x86_64-linux-gnu",
+      },
+      windows: {
+          enabled: false,
+      },
+  },
+  allow_undefined_symbols: true,
+}
+
+cc_library{
+  name: "bluetooth_packets_python3",
+  defaults: [
+    "gd_defaults",
+    "bluetooth_py3_native_extension_defaults"
+  ],
+  host_supported: true,
+  srcs: [
+    "packet/python3_module.cc",
+    "l2cap/fcs.cc",
+    ":BluetoothPacketSources",
+  ],
+  generated_headers: [
+    "BluetoothGeneratedPackets_h",
+  ],
+  generated_sources: [
+    "BluetoothGeneratedPackets_python3_cc",
+  ],
+  header_libs: [
+    "pybind11_headers",
+  ],
+  cflags: [
+    "-fexceptions",
+  ],
+  rtti: true,
+}
diff --git a/gd/cert/android_devices_config.json b/gd/cert/android_devices_config.json
index 1cb500e..2bcbf9d 100644
--- a/gd/cert/android_devices_config.json
+++ b/gd/cert/android_devices_config.json
@@ -18,9 +18,10 @@
                         "-s",
                         "$(serial_number)",
                         "shell",
-                        "/system/bin/stack_with_facade",
+                        "/system/bin/bluetooth_stack_with_facade",
                         "--grpc-port=$(grpc_port)",
                         "--root-server-port=$(grpc_root_server_port)",
+                        "--btsnoop=data/misc/bluetooth/logs/btsnoop_hci.log",
                         "--signal-port=$(signal_port)"
                     ]
                 }
@@ -42,6 +43,7 @@
                         "/system/bin/bluetooth_cert_stack",
                         "--grpc-port=$(grpc_port)",
                         "--root-server-port=$(grpc_root_server_port)",
+                        "--btsnoop=data/misc/bluetooth/logs/btsnoop_hci.log",
                         "--signal-port=$(signal_port)"
                     ]
                 }
diff --git a/gd/cert/bluetooth_packets_python3_setup.py b/gd/cert/bluetooth_packets_python3_setup.py
new file mode 100644
index 0000000..bce14f0
--- /dev/null
+++ b/gd/cert/bluetooth_packets_python3_setup.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+#   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.
+
+
+# Usage:
+# 1. Run envsetup and lunch first in an Android checkout
+# 2. Make target bluetooth_packets_python3 that will generate C++ sources for the
+#    Extension
+# 3. Build only:
+#       python3 bluetooth_packets_python3_setup.py build_ext
+#   Then Find the .so file in build/lib.linux-x86_64-3.X
+# 4. Install:
+#       python3 bluetooth_packets_python3_setup.py install --user
+
+
+import os
+import glob
+from setuptools import setup, Extension
+
+ANDROID_BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+PYBIND11_INCLUDE_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                    "external/python/pybind11/include")
+GD_DIR = os.path.join(ANDROID_BUILD_TOP, "system/bt/gd")
+BT_PACKETS_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                  "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_h/gen")
+BT_PACKETS_PY3_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                      "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_python3_cc/gen")
+
+BT_PACKETS_BASE_SRCS = [
+    os.path.join(GD_DIR, "l2cap/fcs.cc"),
+    os.path.join(GD_DIR, "packet/bit_inserter.cc"),
+    os.path.join(GD_DIR, "packet/byte_inserter.cc"),
+    os.path.join(GD_DIR, "packet/byte_observer.cc"),
+    os.path.join(GD_DIR, "packet/iterator.cc"),
+    os.path.join(GD_DIR, "packet/fragmenting_inserter.cc"),
+    os.path.join(GD_DIR, "packet/packet_view.cc"),
+    os.path.join(GD_DIR, "packet/raw_builder.cc"),
+    os.path.join(GD_DIR, "packet/view.cc"),
+]
+
+BT_PACKETS_PY3_SRCs = \
+  [os.path.join(GD_DIR, "packet/python3_module.cc")] \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "hci", "*.cc")) \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "l2cap", "*.cc")) \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "security", "*.cc"))
+
+bluetooth_packets_python3_module = Extension('bluetooth_packets_python3',
+                                             sources=BT_PACKETS_BASE_SRCS + BT_PACKETS_PY3_SRCs,
+                                             include_dirs=[GD_DIR,
+                                                           BT_PACKETS_GEN_DIR,
+                                                           BT_PACKETS_PY3_GEN_DIR,
+                                                           PYBIND11_INCLUDE_DIR],
+                                             extra_compile_args=['-std=c++17']
+                                             )
+
+setup(name='bluetooth_packets_python3',
+      version='1.0',
+      author="Android Open Source Project",
+      description="""Bluetooth Packet Library""",
+      ext_modules=[bluetooth_packets_python3_module],
+      py_modules=["bluetooth_packets_python3"],
+      )
diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py
index 059c82c..45c2077 100644
--- a/gd/cert/gd_base_test.py
+++ b/gd/cert/gd_base_test.py
@@ -70,7 +70,6 @@
             builtin=True)
 
     def teardown_class(self):
-        self.unregister_controllers()
         if self.rootcanal_running:
             self.rootcanal_process.send_signal(signal.SIGINT)
             rootcanal_return_code = self.rootcanal_process.wait()
diff --git a/gd/cert/gd_cert_device.py b/gd/cert/gd_cert_device.py
index 901fc44..b730b50 100644
--- a/gd/cert/gd_cert_device.py
+++ b/gd/cert/gd_cert_device.py
@@ -21,7 +21,7 @@
 from cert import rootservice_pb2_grpc as cert_rootservice_pb2_grpc
 from hal.cert import api_pb2_grpc as hal_cert_pb2_grpc
 from hci.cert import api_pb2_grpc as hci_cert_pb2_grpc
-from l2cap.cert import api_pb2_grpc as l2cap_cert_pb2_grpc
+from l2cap.classic.cert import api_pb2_grpc as l2cap_cert_pb2_grpc
 
 ACTS_CONTROLLER_CONFIG_NAME = "GdCertDevice"
 ACTS_CONTROLLER_REFERENCE_NAME = "gd_cert_devices"
@@ -67,10 +67,14 @@
         # Cert stubs
         self.rootservice = cert_rootservice_pb2_grpc.RootCertStub(self.grpc_root_server_channel)
         self.hal = hal_cert_pb2_grpc.HciHalCertStub(self.grpc_channel)
+        self.controller_read_only_property = cert_rootservice_pb2_grpc.ReadOnlyPropertyStub(self.grpc_channel)
         self.hci = hci_cert_pb2_grpc.AclManagerCertStub(self.grpc_channel)
         self.l2cap = l2cap_cert_pb2_grpc.L2capModuleCertStub(self.grpc_channel)
 
         # Event streams
+        self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+        self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
+        self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
         self.hci.connection_complete_stream = EventStream(self.hci.FetchConnectionComplete)
         self.hci.disconnection_stream = EventStream(self.hci.FetchDisconnection)
         self.hci.connection_failed_stream = EventStream(self.hci.FetchConnectionFailed)
diff --git a/gd/cert/gd_device.py b/gd/cert/gd_device.py
index faa19cc..2cd49b7 100644
--- a/gd/cert/gd_device.py
+++ b/gd/cert/gd_device.py
@@ -21,7 +21,7 @@
 from facade import rootservice_pb2_grpc as facade_rootservice_pb2_grpc
 from hal import facade_pb2_grpc as hal_facade_pb2_grpc
 from hci import facade_pb2_grpc as hci_facade_pb2_grpc
-from l2cap import facade_pb2_grpc as l2cap_facade_pb2_grpc
+from l2cap.classic import facade_pb2_grpc as l2cap_facade_pb2_grpc
 
 ACTS_CONTROLLER_CONFIG_NAME = "GdDevice"
 ACTS_CONTROLLER_REFERENCE_NAME = "gd_devices"
@@ -67,7 +67,9 @@
         # Facade stubs
         self.rootservice = facade_rootservice_pb2_grpc.RootFacadeStub(self.grpc_root_server_channel)
         self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
+        self.controller_read_only_property = facade_rootservice_pb2_grpc.ReadOnlyPropertyStub(self.grpc_channel)
         self.hci = hci_facade_pb2_grpc.AclManagerFacadeStub(self.grpc_channel)
+        self.hci_classic_security = hci_facade_pb2_grpc.ClassicSecurityManagerFacadeStub(self.grpc_channel)
         self.l2cap = l2cap_facade_pb2_grpc.L2capModuleFacadeStub(self.grpc_channel)
 
         # Event streams
@@ -78,3 +80,6 @@
         self.hci.disconnection_stream = EventStream(self.hci.FetchDisconnection)
         self.hci.connection_failed_stream = EventStream(self.hci.FetchConnectionFailed)
         self.hci.acl_stream = EventStream(self.hci.FetchAclData)
+        self.hci_classic_security.command_complete_stream = EventStream(self.hci_classic_security.FetchCommandCompleteEvent)
+        self.l2cap.packet_stream = EventStream(self.l2cap.FetchL2capData)
+        self.l2cap.connection_complete_stream = EventStream(self.l2cap.FetchConnectionComplete)
diff --git a/gd/cert/gd_device_base.py b/gd/cert/gd_device_base.py
index be609a0..df5f9f2 100644
--- a/gd/cert/gd_device_base.py
+++ b/gd/cert/gd_device_base.py
@@ -17,6 +17,7 @@
 import logging
 import os
 from builtins import open
+import json
 import signal
 import socket
 import subprocess
@@ -61,8 +62,10 @@
             log_path_base, '%s_%s_backing_logs.txt' % (type_identifier, label))
         self.backing_process_logs = open(backing_process_logpath, 'w')
 
-        btsnoop_path = os.path.join(log_path_base, '%s_btsnoop_hci.log' % label)
-        cmd.append("--btsnoop=" + btsnoop_path)
+        cmd_str = json.dumps(cmd)
+        if "--btsnoop=" not in cmd_str:
+            btsnoop_path = os.path.join(log_path_base, '%s_btsnoop_hci.log' % label)
+            cmd.append("--btsnoop=" + btsnoop_path)
 
         tester_signal_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         tester_signal_socket.setsockopt(
diff --git a/gd/cert/grpc_root_server.cc b/gd/cert/grpc_root_server.cc
index 7ed6847..7281867 100644
--- a/gd/cert/grpc_root_server.cc
+++ b/gd/cert/grpc_root_server.cc
@@ -18,11 +18,12 @@
 
 #include <string>
 
+#include "cert/read_only_property_server.h"
 #include "cert/rootservice.grpc.pb.h"
 #include "grpc/grpc_module.h"
 #include "hal/cert/cert.h"
 #include "hci/cert/cert.h"
-#include "l2cap/cert/cert.h"
+#include "l2cap/classic/cert/cert.h"
 #include "os/log.h"
 #include "os/thread.h"
 #include "stack_manager.h"
@@ -53,10 +54,12 @@
         modules.add<::bluetooth::hal::cert::HalCertModule>();
         break;
       case BluetoothModule::HCI:
+        modules.add<::bluetooth::cert::ReadOnlyPropertyServerModule>();
         modules.add<::bluetooth::hci::cert::AclManagerCertModule>();
         break;
       case BluetoothModule::L2CAP:
-        modules.add<::bluetooth::l2cap::cert::L2capModuleCertModule>();
+        modules.add<::bluetooth::cert::ReadOnlyPropertyServerModule>();
+        modules.add<::bluetooth::l2cap::classic::cert::L2capModuleCertModule>();
         break;
       default:
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
@@ -82,6 +85,7 @@
 
     stack_manager_.GetInstance<GrpcModule>()->StopServer();
     grpc_loop_thread_->join();
+    delete grpc_loop_thread_;
 
     stack_manager_.ShutDown();
     delete stack_thread_;
diff --git a/gd/cert/host_only_config.json b/gd/cert/host_only_config.json
index 09d67d2..75e459c 100644
--- a/gd/cert/host_only_config.json
+++ b/gd/cert/host_only_config.json
@@ -19,7 +19,7 @@
                     "label": "stack_under_test",
                     "cmd":
                     [
-                        "$ANDROID_HOST_OUT/bin/stack_with_facade",
+                        "$ANDROID_HOST_OUT/bin/bluetooth_stack_with_facade",
                         "--grpc-port=$(grpc_port)",
                         "--root-server-port=$(grpc_root_server_port)",
                         "--rootcanal-port=$(rootcanal_port)",
diff --git a/gd/cert/read_only_property_server.cc b/gd/cert/read_only_property_server.cc
new file mode 100644
index 0000000..d67c33e
--- /dev/null
+++ b/gd/cert/read_only_property_server.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "cert/read_only_property_server.h"
+#include "hci/controller.h"
+
+namespace bluetooth {
+namespace cert {
+
+class ReadOnlyPropertyService : public ReadOnlyProperty::Service {
+ public:
+  ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {}
+  ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                  ::bluetooth::facade::BluetoothAddress* response) override {
+    auto address = controller_->GetControllerMacAddress().ToString();
+    response->set_address(address);
+    return ::grpc::Status::OK;
+  }
+
+ private:
+  hci::Controller* controller_;
+};
+
+void ReadOnlyPropertyServerModule::ListDependencies(ModuleList* list) {
+  GrpcFacadeModule::ListDependencies(list);
+  list->add<hci::Controller>();
+}
+void ReadOnlyPropertyServerModule::Start() {
+  GrpcFacadeModule::Start();
+  service_ = std::make_unique<ReadOnlyPropertyService>(GetDependency<hci::Controller>());
+}
+void ReadOnlyPropertyServerModule::Stop() {
+  service_.reset();
+  GrpcFacadeModule::Stop();
+}
+::grpc::Service* ReadOnlyPropertyServerModule::GetService() const {
+  return service_.get();
+}
+
+const ModuleFactory ReadOnlyPropertyServerModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new ReadOnlyPropertyServerModule(); });
+
+}  // namespace cert
+}  // namespace bluetooth
diff --git a/gd/l2cap/facade.h b/gd/cert/read_only_property_server.h
similarity index 77%
copy from gd/l2cap/facade.h
copy to gd/cert/read_only_property_server.h
index 734d261..e367537 100644
--- a/gd/l2cap/facade.h
+++ b/gd/cert/read_only_property_server.h
@@ -13,29 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #pragma once
 
+#include <memory>
+
 #include <grpc++/grpc++.h>
+
+#include "cert/rootservice.grpc.pb.h"
 #include "grpc/grpc_module.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace cert {
 
-class L2capModuleFacadeService;
+class ReadOnlyPropertyService;
 
-class L2capModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+class ReadOnlyPropertyServerModule : public ::bluetooth::grpc::GrpcFacadeModule {
  public:
   static const ModuleFactory Factory;
 
   void ListDependencies(ModuleList* list) override;
   void Start() override;
   void Stop() override;
-
   ::grpc::Service* GetService() const override;
 
  private:
-  L2capModuleFacadeService* service_;
+  std::unique_ptr<ReadOnlyPropertyService> service_;
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace cert
+}  // namespace bluetooth
diff --git a/gd/cert/rootservice.proto b/gd/cert/rootservice.proto
index 02bd078..4472bfe 100644
--- a/gd/cert/rootservice.proto
+++ b/gd/cert/rootservice.proto
@@ -2,6 +2,9 @@
 
 package bluetooth.cert;
 
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
 service RootCert {
   rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
   rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
@@ -23,3 +26,7 @@
 message StopStackRequest {}
 
 message StopStackResponse {}
+
+service ReadOnlyProperty {
+  rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
+}
diff --git a/gd/cert/run_cert.sh b/gd/cert/run_cert.sh
index 81fe91e..a85b994 100755
--- a/gd/cert/run_cert.sh
+++ b/gd/cert/run_cert.sh
@@ -1,3 +1,5 @@
 #! /bin/bash
 
-act.py -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/run_device_cert.sh b/gd/cert/run_device_cert.sh
index 44e5a89..7566f65 100755
--- a/gd/cert/run_device_cert.sh
+++ b/gd/cert/run_device_cert.sh
@@ -1,3 +1,5 @@
 #! /bin/bash
 
-act.py -c $ANDROID_BUILD_TOP/system/bt/gd/cert/android_devices_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/android_devices_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/set_up_acts.sh b/gd/cert/set_up_acts.sh
index c8fa38b..ad4e775 100755
--- a/gd/cert/set_up_acts.sh
+++ b/gd/cert/set_up_acts.sh
@@ -46,9 +46,15 @@
     popd
 }
 
-function SetupPython3 {
-    echo "Setting up python3"
-    sudo apt-get install python3-dev
+function SetupPython38 {
+    echo "Setting up python3.8"
+    sudo apt-get install python3.8-dev
+}
+
+function CompileBluetoothPacketsPython3 {
+    echo "bluetooth_packets_python3 is not found, compiling"
+    croot
+    make -j bluetooth_packets_python3
 }
 
 if [[ "${BASH_SOURCE[0]}" == "${0}" ]] ; then
@@ -60,16 +66,41 @@
     SetUpAndroidBuild
 fi
 
-## Check python3 is installed properly
-dpkg -l python3-dev > /dev/null 2>&1
+## Check python3.8 is installed properly
+## Need Python 3.8 because bluetooth_packets_python3 is compiled against
+## Python 3.8 headers
+dpkg -l python3.8-dev > /dev/null 2>&1
 if [[ $? -ne 0 ]] ; then
-    SetupPython3
+    SetupPython38
+fi
+
+## Check bluetooth_packets_python3 is compiled succssfully
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+if [[ $? -ne 0 ]] ; then
+  pushd .
+  CompileBluetoothPacketsPython3
+  popd
+  python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+  if [[ $? -ne 0 ]] ; then
+    echo "Setup failed as bluetooth_packets_python3 cannot be found"
+  else
+    echo "Found bluetooth_packets_python3 after compilation"
+  fi
+else
+  echo "Found bluetooth_packets_python3"
 fi
 
 ## All is good now so go ahead with the acts setup
 pushd .
 cd $ANDROID_BUILD_TOP/tools/test/connectivity/acts/framework/
-sudo python3 setup.py develop
+sudo python3.8 setup.py develop
 if [[ $? -eq 0 ]] ; then
     echo "cert setup complete"
 else
diff --git a/gd/common/Android.bp b/gd/common/Android.bp
index 8eed81a..c923427 100644
--- a/gd/common/Android.bp
+++ b/gd/common/Android.bp
@@ -1,18 +1,16 @@
 filegroup {
     name: "BluetoothCommonSources",
     srcs: [
-        "address.cc",
-        "class_of_device.cc",
+        "link_key.cc",
     ],
 }
 
 filegroup {
     name: "BluetoothCommonTestSources",
     srcs: [
-        "address_unittest.cc",
         "blocking_queue_unittest.cc",
-        "class_of_device_unittest.cc",
         "bidi_queue_unittest.cc",
         "observer_registry_test.cc",
+        "link_key_unittest.cc",
     ],
 }
diff --git a/gd/common/callback_list.h b/gd/common/callback_list.h
new file mode 100644
index 0000000..857b0c7
--- /dev/null
+++ b/gd/common/callback_list.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <utility>
+#include "base/callback_list.h"
+#include "os/handler.h"
+
+/* This file contains CallbackList implementation that will execute callback on provided Handler thread
+
+Example usage inside your class:
+
+private:
+  common::CallbackList<void(int)> callbacks_list_;
+public:
+  std::unique_ptr<common::CallbackList<void(int)>::Subscription> RegisterCallback(
+      const base::RepeatingCallback<void(int)>& cb, os::Handler* handler) {
+    return callbacks_list_.Add({cb, handler});
+  }
+
+  void NotifyAllCallbacks(int value) {
+    callbacks_list_.Notify(value);
+  }
+*/
+
+namespace bluetooth {
+namespace common {
+
+namespace {
+template <typename CallbackType>
+struct CallbackWithHandler {
+  CallbackWithHandler(base::RepeatingCallback<CallbackType> callback, os::Handler* handler)
+      : callback(callback), handler(handler) {}
+
+  bool is_null() const {
+    return callback.is_null();
+  }
+
+  void Reset() {
+    callback.Reset();
+  }
+
+  base::RepeatingCallback<CallbackType> callback;
+  os::Handler* handler;
+};
+
+}  // namespace
+
+template <typename Sig>
+class CallbackList;
+template <typename... Args>
+class CallbackList<void(Args...)> : public base::internal::CallbackListBase<CallbackWithHandler<void(Args...)>> {
+ public:
+  using CallbackType = CallbackWithHandler<void(Args...)>;
+  CallbackList() = default;
+  template <typename... RunArgs>
+  void Notify(RunArgs&&... args) {
+    auto it = this->GetIterator();
+    CallbackType* cb;
+    while ((cb = it.GetNext()) != nullptr) {
+      cb->handler->Post(base::Bind(cb->callback, args...));
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CallbackList);
+};
+
+}  // namespace common
+}  // namespace bluetooth
diff --git a/gd/common/link_key.cc b/gd/common/link_key.cc
new file mode 100644
index 0000000..12b60cd
--- /dev/null
+++ b/gd/common/link_key.cc
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  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 "link_key.h"
+
+namespace bluetooth {
+namespace common {
+
+const LinkKey LinkKey::kExample{
+    {0x4C, 0x68, 0x38, 0x41, 0x39, 0xf5, 0x74, 0xd8, 0x36, 0xbc, 0xf3, 0x4e, 0x9d, 0xfb, 0x01, 0xbf}};
+
+LinkKey::LinkKey(const uint8_t (&data)[16]) {
+  std::copy(data, data + kLength, link_key);
+}
+
+std::string LinkKey::ToString() const {
+  char buffer[33] = "";
+  for (int i = 0; i < 16; i++) {
+    std::snprintf(&buffer[i * 2], 3, "%02x", link_key[i]);
+  }
+  std::string str(buffer);
+  return str;
+}
+
+bool LinkKey::FromString(const std::string& from, bluetooth::common::LinkKey& to) {
+  LinkKey new_link_key;
+
+  if (from.length() != 32) {
+    return false;
+  }
+
+  char* temp = nullptr;
+  for (int i = 0; i < 16; i++) {
+    new_link_key.link_key[i] = strtol(from.substr(i * 2, 2).c_str(), &temp, 16);
+  }
+
+  to = new_link_key;
+  return true;
+}
+
+}  // namespace common
+}  // namespace bluetooth
diff --git a/gd/common/link_key.h b/gd/common/link_key.h
new file mode 100644
index 0000000..b2bf394
--- /dev/null
+++ b/gd/common/link_key.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ *  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>
+
+namespace bluetooth {
+namespace common {
+
+class LinkKey final {
+ public:
+  LinkKey() = default;
+  LinkKey(const uint8_t (&data)[16]);
+
+  static constexpr unsigned int kLength = 16;
+  uint8_t link_key[kLength];
+
+  std::string ToString() const;
+  static bool FromString(const std::string& from, LinkKey& to);
+
+  static const LinkKey kExample;
+};
+
+}  // namespace common
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/common/link_key_unittest.cc b/gd/common/link_key_unittest.cc
new file mode 100644
index 0000000..6529564
--- /dev/null
+++ b/gd/common/link_key_unittest.cc
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ *  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 "common/link_key.h"
+#include <gtest/gtest.h>
+#include "os/log.h"
+
+using bluetooth::common::LinkKey;
+
+static const char* test_link_key = "4c68384139f574d836bcf34e9dfb01bf\0";
+
+TEST(LinkKeyUnittest, test_constructor_array) {
+  uint8_t data[LinkKey::kLength] = {0x4c, 0x87, 0x49, 0xe1, 0x2e, 0x55, 0x0f, 0x7f,
+                                    0x60, 0x8b, 0x4f, 0x96, 0xd7, 0xc5, 0xbc, 0x2a};
+
+  LinkKey link_key(data);
+
+  for (int i = 0; i < LinkKey::kLength; i++) {
+    ASSERT_EQ(data[i], link_key.link_key[i]);
+  }
+}
+
+TEST(LinkKeyUnittest, test_from_str) {
+  LinkKey link_key;
+  LinkKey::FromString(test_link_key, link_key);
+
+  for (int i = 0; i < LinkKey::kLength; i++) {
+    ASSERT_EQ(LinkKey::kExample.link_key[i], link_key.link_key[i]);
+  }
+}
+
+TEST(LinkKeyUnittest, test_to_str) {
+  std::string str = LinkKey::kExample.ToString();
+  ASSERT_STREQ(str.c_str(), test_link_key);
+}
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/common/testing/bind_test_util.h
similarity index 78%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/common/testing/bind_test_util.h
index 8a08509..7db9204 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/common/testing/bind_test_util.h
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#pragma once
+
+#include "base/test/bind_test_util.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace common {
+namespace testing {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+using base::BindLambdaForTesting;
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace testing
+}  // namespace common
+}  // namespace bluetooth
diff --git a/gd/common/testing/wired_pair_of_bidi_queues.h b/gd/common/testing/wired_pair_of_bidi_queues.h
new file mode 100644
index 0000000..92c6a1f
--- /dev/null
+++ b/gd/common/testing/wired_pair_of_bidi_queues.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ *  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 <memory>
+
+#include "common/bidi_queue.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/bit_inserter.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace common {
+namespace testing {
+
+/* This class is a pair of BiDiQueues, that have down ends "wired" together. It can be used i.e. to mock L2cap
+ * interface, and provide two queues, where each sends packets of type A, and receives packets of type B */
+template <class A, class B, std::unique_ptr<B> (*A_TO_B)(std::unique_ptr<A>)>
+class WiredPairOfBiDiQueues {
+  void dequeue_callback_a() {
+    auto down_thing = queue_a_.GetDownEnd()->TryDequeue();
+    if (!down_thing) LOG_ERROR("Received dequeue, but no data ready...");
+
+    down_buffer_b_.Enqueue(A_TO_B(std::move(down_thing)), handler_);
+  }
+
+  void dequeue_callback_b() {
+    auto down_thing = queue_b_.GetDownEnd()->TryDequeue();
+    if (!down_thing) LOG_ERROR("Received dequeue, but no data ready...");
+
+    down_buffer_a_.Enqueue(A_TO_B(std::move(down_thing)), handler_);
+  }
+
+  os::Handler* handler_;
+  common::BidiQueue<B, A> queue_a_{10};
+  common::BidiQueue<B, A> queue_b_{10};
+  os::EnqueueBuffer<B> down_buffer_a_{queue_a_.GetDownEnd()};
+  os::EnqueueBuffer<B> down_buffer_b_{queue_b_.GetDownEnd()};
+
+ public:
+  WiredPairOfBiDiQueues(os::Handler* handler) : handler_(handler) {
+    queue_a_.GetDownEnd()->RegisterDequeue(
+        handler_, common::Bind(&WiredPairOfBiDiQueues::dequeue_callback_a, common::Unretained(this)));
+    queue_b_.GetDownEnd()->RegisterDequeue(
+        handler_, common::Bind(&WiredPairOfBiDiQueues::dequeue_callback_b, common::Unretained(this)));
+  }
+
+  ~WiredPairOfBiDiQueues() {
+    queue_a_.GetDownEnd()->UnregisterDequeue();
+    queue_b_.GetDownEnd()->UnregisterDequeue();
+  }
+
+  /* This methd returns the UpEnd of queue A */
+  common::BidiQueueEnd<A, B>* GetQueueAUpEnd() {
+    return queue_a_.GetUpEnd();
+  }
+
+  /* This methd returns the UpEnd of queue B */
+  common::BidiQueueEnd<A, B>* GetQueueBUpEnd() {
+    return queue_b_.GetUpEnd();
+  }
+};
+
+namespace {
+std::unique_ptr<packet::PacketView<packet::kLittleEndian>> BuilderToView(
+    std::unique_ptr<packet::BasePacketBuilder> up_thing) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  bluetooth::packet::BitInserter i(*bytes);
+  bytes->reserve(up_thing->size());
+  up_thing->Serialize(i);
+  return std::make_unique<packet::PacketView<packet::kLittleEndian>>(bytes);
+}
+}  // namespace
+
+using WiredPairOfL2capQueues =
+    WiredPairOfBiDiQueues<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>, BuilderToView>;
+
+}  // namespace testing
+}  // namespace common
+}  // namespace bluetooth
diff --git a/gd/crypto_toolbox/crypto_toolbox.cc b/gd/crypto_toolbox/crypto_toolbox.cc
index 1b2c06d..6582633 100644
--- a/gd/crypto_toolbox/crypto_toolbox.cc
+++ b/gd/crypto_toolbox/crypto_toolbox.cc
@@ -161,5 +161,43 @@
   return h6(iltk, keyID_brle);
 }
 
+Octet16 c1(const Octet16& k, const Octet16& r, const uint8_t* pres, const uint8_t* preq, const uint8_t iat,
+           const uint8_t* ia, const uint8_t rat, const uint8_t* ra) {
+  Octet16 p1;
+  auto it = p1.begin();
+  it = std::copy(pres, pres + 7, it);
+  it = std::copy(preq, preq + 7, it);
+  it = std::copy(&rat, &rat + 1, it);
+  it = std::copy(&iat, &iat + 1, it);
+
+  for (uint8_t i = 0; i < OCTET16_LEN; i++) {
+    p1[i] = r[i] ^ p1[i];
+  }
+
+  Octet16 p1bis = aes_128(k, p1);
+
+  std::array<uint8_t, 4> padding{0};
+  Octet16 p2;
+  it = p2.begin();
+  it = std::copy(padding.begin(), padding.end(), it);
+  it = std::copy(ia, ia + 6, it);
+  it = std::copy(ra, ra + 6, it);
+
+  for (uint8_t i = 0; i < OCTET16_LEN; i++) {
+    p2[i] = p1bis[i] ^ p2[i];
+  }
+
+  return aes_128(k, p2);
+}
+
+Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2) {
+  Octet16 text{0};
+  constexpr uint8_t BT_OCTET8_LEN = 8;
+  memcpy(text.data(), r1.data(), BT_OCTET8_LEN);
+  memcpy(text.data() + BT_OCTET8_LEN, r2.data(), BT_OCTET8_LEN);
+
+  return aes_128(k, text);
+}
+
 }  // namespace crypto_toolbox
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/crypto_toolbox/crypto_toolbox.h b/gd/crypto_toolbox/crypto_toolbox.h
index 899c958..25f7f69 100644
--- a/gd/crypto_toolbox/crypto_toolbox.h
+++ b/gd/crypto_toolbox/crypto_toolbox.h
@@ -24,6 +24,10 @@
 constexpr int OCTET16_LEN = 16;
 using Octet16 = std::array<uint8_t, OCTET16_LEN>;
 
+Octet16 c1(const Octet16& k, const Octet16& r, const uint8_t* pres, const uint8_t* preq, const uint8_t iat,
+           const uint8_t* ia, const uint8_t rat, const uint8_t* ra);
+Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2);
+
 extern Octet16 aes_128(const Octet16& key, const Octet16& message);
 extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length);
 extern Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z);
diff --git a/gd/facade/grpc_root_server.cc b/gd/facade/grpc_root_server.cc
index 0e750bf..29ccc59 100644
--- a/gd/facade/grpc_root_server.cc
+++ b/gd/facade/grpc_root_server.cc
@@ -18,11 +18,12 @@
 
 #include <string>
 
+#include "facade/read_only_property_server.h"
 #include "facade/rootservice.grpc.pb.h"
 #include "grpc/grpc_module.h"
 #include "hal/facade.h"
 #include "hci/facade.h"
-#include "l2cap/facade.h"
+#include "l2cap/classic/facade.h"
 #include "os/log.h"
 #include "os/thread.h"
 #include "stack_manager.h"
@@ -53,10 +54,13 @@
         modules.add<::bluetooth::hal::HciHalFacadeModule>();
         break;
       case BluetoothModule::HCI:
+        modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
         modules.add<::bluetooth::hci::AclManagerFacadeModule>();
+        modules.add<::bluetooth::hci::ClassicSecurityManagerFacadeModule>();
         break;
       case BluetoothModule::L2CAP:
-        modules.add<::bluetooth::l2cap::L2capModuleFacadeModule>();
+        modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
+        modules.add<::bluetooth::l2cap::classic::L2capModuleFacadeModule>();
         break;
       default:
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
@@ -82,6 +86,7 @@
 
     stack_manager_.GetInstance<GrpcModule>()->StopServer();
     grpc_loop_thread_->join();
+    delete grpc_loop_thread_;
 
     stack_manager_.ShutDown();
     delete stack_thread_;
diff --git a/gd/facade/read_only_property_server.cc b/gd/facade/read_only_property_server.cc
new file mode 100644
index 0000000..3c57b87
--- /dev/null
+++ b/gd/facade/read_only_property_server.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "facade/read_only_property_server.h"
+#include "hci/controller.h"
+
+namespace bluetooth {
+namespace facade {
+
+class ReadOnlyPropertyService : public ReadOnlyProperty::Service {
+ public:
+  ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {}
+  ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                  ::bluetooth::facade::BluetoothAddress* response) override {
+    auto address = controller_->GetControllerMacAddress().ToString();
+    response->set_address(address);
+    return ::grpc::Status::OK;
+  }
+
+ private:
+  hci::Controller* controller_;
+};
+
+void ReadOnlyPropertyServerModule::ListDependencies(ModuleList* list) {
+  GrpcFacadeModule::ListDependencies(list);
+  list->add<hci::Controller>();
+}
+void ReadOnlyPropertyServerModule::Start() {
+  GrpcFacadeModule::Start();
+  service_ = std::make_unique<ReadOnlyPropertyService>(GetDependency<hci::Controller>());
+}
+void ReadOnlyPropertyServerModule::Stop() {
+  service_.reset();
+  GrpcFacadeModule::Stop();
+}
+::grpc::Service* ReadOnlyPropertyServerModule::GetService() const {
+  return service_.get();
+}
+
+const ModuleFactory ReadOnlyPropertyServerModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new ReadOnlyPropertyServerModule(); });
+
+}  // namespace facade
+}  // namespace bluetooth
diff --git a/gd/l2cap/facade.h b/gd/facade/read_only_property_server.h
similarity index 77%
copy from gd/l2cap/facade.h
copy to gd/facade/read_only_property_server.h
index 734d261..dfac424 100644
--- a/gd/l2cap/facade.h
+++ b/gd/facade/read_only_property_server.h
@@ -13,29 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #pragma once
 
+#include <memory>
+
 #include <grpc++/grpc++.h>
+
+#include "facade/rootservice.grpc.pb.h"
 #include "grpc/grpc_module.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace facade {
 
-class L2capModuleFacadeService;
+class ReadOnlyPropertyService;
 
-class L2capModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+class ReadOnlyPropertyServerModule : public ::bluetooth::grpc::GrpcFacadeModule {
  public:
   static const ModuleFactory Factory;
 
   void ListDependencies(ModuleList* list) override;
   void Start() override;
   void Stop() override;
-
   ::grpc::Service* GetService() const override;
 
  private:
-  L2capModuleFacadeService* service_;
+  std::unique_ptr<ReadOnlyPropertyService> service_;
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace facade
+}  // namespace bluetooth
diff --git a/gd/facade/rootservice.proto b/gd/facade/rootservice.proto
index 7bf45ca..eec30ad 100644
--- a/gd/facade/rootservice.proto
+++ b/gd/facade/rootservice.proto
@@ -2,6 +2,9 @@
 
 package bluetooth.facade;
 
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
 service RootFacade {
   rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
   rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
@@ -23,3 +26,7 @@
 message StopStackRequest {}
 
 message StopStackResponse {}
+
+service ReadOnlyProperty {
+  rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
+}
diff --git a/gd/fuzz_test.cc b/gd/fuzz_test.cc
new file mode 100644
index 0000000..ef358b5
--- /dev/null
+++ b/gd/fuzz_test.cc
@@ -0,0 +1,29 @@
+/*
+ * 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 <stddef.h>
+#include <stdint.h>
+
+extern void RunL2capClassicDynamicChannelAllocatorFuzzTest(const uint8_t* data, size_t size);
+extern void RunL2capPacketFuzzTest(const uint8_t* data, size_t size);
+extern void RunHciPacketFuzzTest(const uint8_t* data, size_t size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  RunL2capClassicDynamicChannelAllocatorFuzzTest(data, size);
+  RunL2capPacketFuzzTest(data, size);
+  RunHciPacketFuzzTest(data, size);
+  return 0;
+}
\ No newline at end of file
diff --git a/gd/grpc/grpc_module.cc b/gd/grpc/grpc_module.cc
index 5f4c862..07d7bb0 100644
--- a/gd/grpc/grpc_module.cc
+++ b/gd/grpc/grpc_module.cc
@@ -102,6 +102,10 @@
   }
 }
 
+std::string GrpcModule::ToString() const {
+  return "Grpc Module";
+}
+
 const ::bluetooth::ModuleFactory GrpcModule::Factory = ::bluetooth::ModuleFactory([]() {
   return new GrpcModule();
 });
@@ -119,5 +123,9 @@
   GetDependency<GrpcModule>()->Unregister(this);
 }
 
+std::string GrpcFacadeModule::ToString() const {
+  return "Grpc Facade Module";
+}
+
 }  // namespace grpc
 }  // namespace bluetooth
diff --git a/gd/grpc/grpc_module.h b/gd/grpc/grpc_module.h
index 4730b06..15d3126 100644
--- a/gd/grpc/grpc_module.h
+++ b/gd/grpc/grpc_module.h
@@ -49,6 +49,8 @@
 
   void Stop() override;
 
+  std::string ToString() const override;
+
  private:
   bool started_;
   std::unique_ptr<::grpc::Server> server_ = nullptr;
@@ -70,6 +72,8 @@
   virtual void OnServerStarted(::grpc::ServerCompletionQueue* cq) {}
 
   virtual void OnServerStopped() {}
+
+  std::string ToString() const override;
 };
 
 }  // namespace grpc
diff --git a/gd/hal/cert/cert.cc b/gd/hal/cert/cert.cc
index a50b1f7..12240d3 100644
--- a/gd/hal/cert/cert.cc
+++ b/gd/hal/cert/cert.cc
@@ -24,6 +24,7 @@
 #include "grpc/grpc_event_stream.h"
 #include "hal/cert/api.grpc.pb.h"
 #include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
 #include "hci/hci_packets.h"
 
 namespace bluetooth {
@@ -46,11 +47,7 @@
                                      ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
     can_send_hci_command_ = false;
-    auto packet = hci::ResetBuilder::Create();
-    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-    hci::BitInserter it(*packet_bytes);
-    packet->Serialize(it);
-    hal_->sendHciCommand(*packet_bytes);
+    hal_->sendHciCommand(SerializePacket(hci::ResetBuilder::Create()));
     std::this_thread::sleep_for(std::chrono::milliseconds(300));
     while (!can_send_hci_command_) {
       cv_.wait(lock);
@@ -79,12 +76,7 @@
         break;
     }
 
-    auto packet = hci::WriteScanEnableBuilder::Create(scan_enable);
-    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-    hci::BitInserter it(*packet_bytes);
-    packet->Serialize(it);
-    hal_->sendHciCommand(*packet_bytes);
-
+    hal_->sendHciCommand(SerializePacket(hci::WriteScanEnableBuilder::Create(scan_enable)));
     while (!can_send_hci_command_) {
       cv_.wait(lock);
     }
diff --git a/gd/hal/cert/simple_hal_test.py b/gd/hal/cert/simple_hal_test.py
index 1965e9c..d8e54d0 100644
--- a/gd/hal/cert/simple_hal_test.py
+++ b/gd/hal/cert/simple_hal_test.py
@@ -53,6 +53,9 @@
         self.cert_device.hal.SendHciResetCommand(empty_pb2.Empty())
 
         self.hci_event_stream = self.device_under_test.hal.hci_event_stream
+        self.cert_hci_event_stream = self.cert_device.hal.hci_event_stream
+        self.hci_acl_stream = self.device_under_test.hal.hci_acl_stream
+        self.cert_hci_acl_stream = self.cert_device.hal.hci_acl_stream
 
     def teardown_test(self):
         self.device_under_test.rootservice.StopStack(
@@ -61,6 +64,8 @@
         self.cert_device.rootservice.StopStack(
             cert_rootservice_pb2.StopStackRequest()
         )
+        self.hci_event_stream.clear_event_buffer()
+        self.cert_hci_event_stream.clear_event_buffer()
 
     def test_none_event(self):
         self.hci_event_stream.clear_event_buffer()
@@ -106,3 +111,202 @@
             # Expecting an HCI Event (code 0x02, length 0x0f)
         )
         self.hci_event_stream.unsubscribe()
+
+    def test_le_ad_scan_cert_advertises(self):
+        self.hci_event_stream.subscribe()
+
+        # Set the LE Address to 0D:05:04:03:02:01
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+            )
+        )
+        # Set the LE Scan parameters (active, 40ms, 20ms, Random, 
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x0B\x20\x07\x01\x40\x00\x20\x00\x01\x00'
+            )
+        )
+        # Enable Scanning (Disable duplicate filtering)
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0C\x20\x02\x01\x00'
+            )
+        )
+
+        # Set the LE Address to 0C:05:04:03:02:01
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+            )
+        )
+        # Set LE Advertising parameters
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x06\x20\x0F\x00\x02\x00\x03\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+            )
+        )
+        # Set LE Advertising data
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x08\x20\x20\x0C\x0A\x09Im_A_Cert\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+            )
+        )
+        # Enable Advertising
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0A\x20\x01\x01'
+            )
+        )
+        self.hci_event_stream.assert_event_occurs(
+            lambda packet: b'Im_A_Cert' in packet.payload
+            # Expecting an HCI Event (code 0x3e, length 0x13, subevent 0x01 )
+        )
+        # Disable Advertising
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0A\x20\x01\x00'
+            )
+        )
+        # Disable Scanning
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0C\x20\x02\x00\x00'
+            )
+        )
+        self.hci_event_stream.unsubscribe()
+
+    def test_le_connection_dut_advertises(self):
+        self.hci_event_stream.subscribe()
+        self.cert_hci_event_stream.subscribe()
+        self.hci_acl_stream.subscribe()
+        self.cert_hci_acl_stream.subscribe()
+
+        # Set the CERT LE Address to 0C:05:04:03:02:01
+        self.cert_device.hal.SendHciCommand(
+            hal_cert_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+            )
+        )
+
+        # Direct connect to 0D:05:04:03:02:01
+        self.cert_device.hal.SendHciCommand(
+            hal_cert_pb2.HciCommandPacket(
+               payload=b'\x0D\x20\x19\x11\x01\x22\x02\x00\x01\x01\x02\x03\x04\x05\x0D\x01\x06\x00\x70\x0C\x40\x00\x03\x07\x01\x00\x02\x00'
+            )
+        )
+
+        # Set the LE Address to 0D:05:04:03:02:01
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+            )
+        )
+        # Set LE Advertising parameters
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x06\x20\x0F\x80\x00\x00\x04\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+            )
+        )
+        # Set LE Advertising data
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x08\x20\x20\x0C\x0B\x09Im_The_DUT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+            )
+        )
+        # Enable Advertising
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0A\x20\x01\x01'
+            )
+        )
+        # LeConnectionComplete TODO: Extract the handle
+        self.cert_hci_event_stream.assert_event_occurs(
+            lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+        )
+        # LeConnectionComplete TODO: Extract the handle
+        self.hci_event_stream.assert_event_occurs(
+            lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+        )
+        # Send ACL Data
+        self.device_under_test.hal.SendHciAcl(
+            hal_facade_pb2.HciAclPacket(
+               payload=b'\xfe\x0e\x0b\x00SomeAclData'
+            )
+        )
+        # Send ACL Data
+        self.cert_device.hal.SendHciAcl(
+            hal_facade_pb2.HciAclPacket(
+               payload=b'\xfe\x0e\x0f\x00SomeMoreAclData'
+            )
+        )
+        self.cert_hci_acl_stream.assert_event_occurs(
+            lambda packet: b'\xfe\x0e\x0b\x00SomeAclData' in packet.payload
+        )
+        self.hci_acl_stream.assert_event_occurs(
+            lambda packet: b'\xfe\x0e\x0f\x00SomeMoreAclData' in packet.payload
+        )
+
+        self.hci_event_stream.unsubscribe()
+        self.cert_hci_event_stream.unsubscribe()
+        self.hci_acl_stream.unsubscribe()
+        self.cert_hci_acl_stream.unsubscribe()
+
+    def test_le_white_list_connection_cert_advertises(self):
+        self.hci_event_stream.subscribe()
+        self.cert_hci_event_stream.subscribe()
+
+        # Set the LE Address to 0D:05:04:03:02:01
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+            )
+        )
+        # Add the cert device to the white list (Random 0C:05:04:03:02:01)
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x11\x20\x07\x01\x01\x02\x03\x04\x05\x0C'
+            )
+        )
+        # Connect using the white list
+        self.device_under_test.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0D\x20\x19\x11\x01\x22\x02\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x01\x06\x00\x70\x0C\x40\x00\x03\x07\x01\x00\x02\x00'
+            )
+        )
+
+        # Set the LE Address to 0C:05:04:03:02:01
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+            )
+        )
+        # Set LE Advertising parameters
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x06\x20\x0F\x00\x02\x00\x03\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+            )
+        )
+        # Set LE Advertising data
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x08\x20\x20\x0C\x0A\x09Im_A_Cert\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+            )
+        )
+        # Enable Advertising
+        self.cert_device.hal.SendHciCommand(
+            hal_facade_pb2.HciCommandPacket(
+               payload=b'\x0A\x20\x01\x01'
+            )
+        )
+        # LeConnectionComplete
+        self.cert_hci_event_stream.assert_event_occurs(
+            lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+        )
+        # LeConnectionComplete
+        self.hci_event_stream.assert_event_occurs(
+            lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+        )
+
+        self.hci_event_stream.unsubscribe()
+        self.cert_hci_event_stream.unsubscribe()
diff --git a/gd/hal/facade.cc b/gd/hal/facade.cc
index 7e486ac..ce25103 100644
--- a/gd/hal/facade.cc
+++ b/gd/hal/facade.cc
@@ -24,6 +24,7 @@
 #include "grpc/grpc_event_stream.h"
 #include "hal/facade.grpc.pb.h"
 #include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
 #include "hci/hci_packets.h"
 
 using ::grpc::ServerAsyncResponseWriter;
@@ -53,11 +54,7 @@
                                      ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
     can_send_hci_command_ = false;
-    auto packet = hci::ResetBuilder::Create();
-    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-    hci::BitInserter it(*packet_bytes);
-    packet->Serialize(it);
-    hal_->sendHciCommand(*packet_bytes);
+    hal_->sendHciCommand(SerializePacket(hci::ResetBuilder::Create()));
     while (!can_send_hci_command_) {
       cv_.wait(lock);
     }
@@ -70,12 +67,8 @@
     std::unique_lock<std::mutex> lock(mutex_);
     can_send_hci_command_ = false;
     bool enable = request->enable();
-    auto packet = hci::WriteLoopbackModeBuilder::Create(enable ? hci::LoopbackMode::ENABLE_LOCAL
-                                                               : hci::LoopbackMode::NO_LOOPBACK);
-    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-    hci::BitInserter it(*packet_bytes);
-    packet->Serialize(it);
-    hal_->sendHciCommand(*packet_bytes);
+    hal_->sendHciCommand(SerializePacket(hci::WriteLoopbackModeBuilder::Create(
+        enable ? hci::LoopbackMode::ENABLE_LOCAL : hci::LoopbackMode::NO_LOOPBACK)));
     while (!can_send_hci_command_) {
       cv_.wait(lock);
     }
@@ -86,12 +79,11 @@
                             ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
     can_send_hci_command_ = false;
-    auto packet = hci::InquiryBuilder::Create(0x33 /* LAP=0x9e8b33 */, static_cast<uint8_t>(request->length()),
-                                              static_cast<uint8_t>(request->num_responses()));
-    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-    hci::BitInserter it(*packet_bytes);
-    packet->Serialize(it);
-    hal_->sendHciCommand(*packet_bytes);
+    hci::Lap lap;
+    lap.lap_ = 0x33;
+
+    hal_->sendHciCommand(SerializePacket(hci::InquiryBuilder::Create(lap, static_cast<uint8_t>(request->length()),
+                                                                     static_cast<uint8_t>(request->num_responses()))));
     while (!can_send_hci_command_) {
       cv_.wait(lock);
     }
diff --git a/gd/hal/hci_hal_android_hidl.cc b/gd/hal/hci_hal_android_hidl.cc
index 1954862..7e45d89 100644
--- a/gd/hal/hci_hal_android_hidl.cc
+++ b/gd/hal/hci_hal_android_hidl.cc
@@ -113,6 +113,7 @@
 }  // namespace
 
 const std::string SnoopLogger::DefaultFilePath = "/data/misc/bluetooth/logs/btsnoop_hci.log";
+const bool SnoopLogger::AlwaysFlush = false;
 
 class HciHalHidl : public HciHal {
  public:
diff --git a/gd/hal/hci_hal_host_rootcanal.cc b/gd/hal/hci_hal_host_rootcanal.cc
index f8e4c61..11809ba 100644
--- a/gd/hal/hci_hal_host_rootcanal.cc
+++ b/gd/hal/hci_hal_host_rootcanal.cc
@@ -87,6 +87,7 @@
 namespace hal {
 
 const std::string SnoopLogger::DefaultFilePath = "/tmp/btsnoop_hci.log";
+const bool SnoopLogger::AlwaysFlush = true;
 
 class HciHalHostRootcanal : public HciHal {
  public:
diff --git a/gd/hal/hci_hal_host_rootcanal_test.cc b/gd/hal/hci_hal_host_rootcanal_test.cc
index e06c803..9783e84 100644
--- a/gd/hal/hci_hal_host_rootcanal_test.cc
+++ b/gd/hal/hci_hal_host_rootcanal_test.cc
@@ -16,6 +16,7 @@
 
 #include "hal/hci_hal_host_rootcanal.h"
 #include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
 
 #include <fcntl.h>
 #include <netdb.h>
@@ -35,6 +36,7 @@
 #include "os/log.h"
 #include "os/thread.h"
 #include "os/utils.h"
+#include "packet/raw_builder.h"
 
 using ::bluetooth::os::Thread;
 
@@ -377,6 +379,11 @@
   }
 }
 
+TEST(HciHalHidlTest, serialize) {
+  std::vector<uint8_t> bytes = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  auto packet_bytes = hal::SerializePacket(std::unique_ptr<packet::BasePacketBuilder>(new packet::RawBuilder(bytes)));
+  EXPECT_EQ(bytes, packet_bytes);
+}
 }  // namespace
 }  // namespace hal
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/hal/serialize_packet.h
similarity index 63%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/hal/serialize_packet.h
index 8a08509..621dcec 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/hal/serialize_packet.h
@@ -14,12 +14,22 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#pragma once
+
+#include <memory>
+
+#include "packet/base_packet_builder.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace hal {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+inline std::vector<uint8_t> SerializePacket(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  std::vector<uint8_t> packet_bytes;
+  packet_bytes.reserve(packet->size());
+  packet::BitInserter it(packet_bytes);
+  packet->Serialize(it);
+  return packet_bytes;
+}
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace hal
+}  // namespace bluetooth
diff --git a/gd/hal/snoop_logger.cc b/gd/hal/snoop_logger.cc
index 874fb31..3574b17 100644
--- a/gd/hal/snoop_logger.cc
+++ b/gd/hal/snoop_logger.cc
@@ -119,6 +119,7 @@
                                     .type = static_cast<uint8_t>(type)};
   btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(btsnoop_packet_header_t));
   btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size());
+  if (AlwaysFlush) btsnoop_ostream_.flush();
 }
 
 void SnoopLogger::ListDependencies(ModuleList* list) {
diff --git a/gd/hal/snoop_logger.h b/gd/hal/snoop_logger.h
index 4e0b90d..8021c2b 100644
--- a/gd/hal/snoop_logger.h
+++ b/gd/hal/snoop_logger.h
@@ -35,6 +35,8 @@
   static const std::string DefaultFilePath;
   // Set File Path before module is started to ensure all packets are written to the right file
   static void SetFilePath(const std::string& filename);
+  // Flag to allow flush into persistent memory on every packet captured. This is enabled on host for debugging.
+  static const bool AlwaysFlush;
 
   enum class PacketType {
     CMD = 1,
diff --git a/gd/hci/Android.bp b/gd/hci/Android.bp
index ad6fc96..8784a49 100644
--- a/gd/hci/Android.bp
+++ b/gd/hci/Android.bp
@@ -2,8 +2,16 @@
     name: "BluetoothHciSources",
     srcs: [
         "acl_manager.cc",
+        "acl_fragmenter.cc",
+        "address.cc",
+        "classic_security_manager.cc",
+        "class_of_device.cc",
         "controller.cc",
+        "device.cc",
+        "device_database.cc",
         "hci_layer.cc",
+        "le_advertising_manager.cc",
+        "le_scanning_manager.cc",
     ],
 }
 
@@ -12,8 +20,18 @@
     srcs: [
         "acl_builder_test.cc",
         "acl_manager_test.cc",
+        "address_unittest.cc",
+        "address_with_type_test.cc",
+        "class_of_device_unittest.cc",
+        "classic_security_manager_test.cc",
         "controller_test.cc",
+        "device_test.cc",
+        "device_database_test.cc",
+        "dual_device_test.cc",
         "hci_layer_test.cc",
+        "hci_packets_test.cc",
+        "le_advertising_manager_test.cc",
+        "le_scanning_manager_test.cc",
     ],
 }
 
@@ -30,3 +48,10 @@
         "cert/cert.cc",
     ],
 }
+
+filegroup {
+    name: "BluetoothHciFuzzTestSources",
+    srcs: [
+        "hci_packets_fuzz_test.cc",
+    ],
+}
diff --git a/gd/hci/acl_fragmenter.cc b/gd/hci/acl_fragmenter.cc
new file mode 100644
index 0000000..fa3b31d
--- /dev/null
+++ b/gd/hci/acl_fragmenter.cc
@@ -0,0 +1,37 @@
+/*
+ * 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 "hci/acl_fragmenter.h"
+
+#include "os/log.h"
+#include "packet/fragmenting_inserter.h"
+
+namespace bluetooth {
+namespace hci {
+
+AclFragmenter::AclFragmenter(size_t mtu, std::unique_ptr<packet::BasePacketBuilder> packet)
+    : mtu_(mtu), packet_(std::move(packet)) {}
+
+std::vector<std::unique_ptr<packet::RawBuilder>> AclFragmenter::GetFragments() {
+  std::vector<std::unique_ptr<packet::RawBuilder>> to_return;
+  packet::FragmentingInserter fragmenting_inserter(mtu_, std::back_insert_iterator(to_return));
+  packet_->Serialize(fragmenting_inserter);
+  fragmenting_inserter.finalize();
+  return to_return;
+}
+
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/acl_fragmenter.h b/gd/hci/acl_fragmenter.h
new file mode 100644
index 0000000..4bc3d06
--- /dev/null
+++ b/gd/hci/acl_fragmenter.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/base_packet_builder.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AclFragmenter {
+ public:
+  AclFragmenter(size_t mtu, std::unique_ptr<packet::BasePacketBuilder> input);
+  virtual ~AclFragmenter() = default;
+
+  std::vector<std::unique_ptr<packet::RawBuilder>> GetFragments();
+
+ private:
+  size_t mtu_;
+  std::unique_ptr<packet::BasePacketBuilder> packet_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/acl_manager.cc b/gd/hci/acl_manager.cc
index dd3878a..2852b6c 100644
--- a/gd/hci/acl_manager.cc
+++ b/gd/hci/acl_manager.cc
@@ -17,9 +17,11 @@
 #include "hci/acl_manager.h"
 
 #include <future>
+#include <queue>
 #include <set>
 #include <utility>
 
+#include "acl_fragmenter.h"
 #include "acl_manager.h"
 #include "common/bidi_queue.h"
 #include "hci/controller.h"
@@ -28,15 +30,21 @@
 namespace bluetooth {
 namespace hci {
 
+constexpr uint16_t kQualcommDebugHandle = 0xedc;
+
 using common::Bind;
 using common::BindOnce;
 
 struct AclManager::acl_connection {
+  acl_connection(AddressWithType address_with_type) : address_with_type_(address_with_type) {}
   friend AclConnection;
+  AddressWithType address_with_type_;
   std::unique_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10);
   bool is_disconnected_ = false;
   ErrorCode disconnect_reason_;
+  os::Handler* command_complete_handler_ = nullptr;
   os::Handler* disconnect_handler_ = nullptr;
+  ConnectionManagementCallbacks* command_complete_callbacks_;
   common::OnceCallback<void(ErrorCode)> on_disconnect_callback_;
   // Round-robin: Track if dequeue is registered for this connection
   bool is_registered_ = false;
@@ -48,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>();
@@ -61,7 +69,7 @@
         common::Bind(&impl::incoming_acl_credits, common::Unretained(this)), handler_);
 
     // TODO: determine when we should reject connection
-    should_accept_connection_ = common::Bind([](common::Address, common::ClassOfDevice) { return true; });
+    should_accept_connection_ = common::Bind([](Address, ClassOfDevice) { return true; });
     hci_queue_end_ = hci_layer_->GetAclQueueEnd();
     hci_queue_end_->RegisterDequeue(
         handler_, common::Bind(&impl::dequeue_and_route_acl_packet_to_connection, common::Unretained(this)));
@@ -71,12 +79,36 @@
                                      Bind(&impl::on_disconnection_complete, common::Unretained(this)), handler_);
     hci_layer_->RegisterEventHandler(EventCode::CONNECTION_REQUEST,
                                      Bind(&impl::on_incoming_connection, common::Unretained(this)), handler_);
+    hci_layer_->RegisterLeEventHandler(SubeventCode::CONNECTION_COMPLETE,
+                                       Bind(&impl::on_le_connection_complete, common::Unretained(this)), handler_);
+    hci_layer_->RegisterLeEventHandler(SubeventCode::ENHANCED_CONNECTION_COMPLETE,
+                                       Bind(&impl::on_le_enhanced_connection_complete, common::Unretained(this)),
+                                       handler_);
+    hci_layer_->RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGED,
+                                     Bind(&impl::on_connection_packet_type_changed, common::Unretained(this)),
+                                     handler_);
+    hci_layer_->RegisterEventHandler(EventCode::AUTHENTICATION_COMPLETE,
+                                     Bind(&impl::on_authentication_complete, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::READ_CLOCK_OFFSET_COMPLETE,
+                                     Bind(&impl::on_read_clock_offset_complete, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::MODE_CHANGE, Bind(&impl::on_mode_change, common::Unretained(this)),
+                                     handler_);
+    hci_layer_->RegisterEventHandler(EventCode::QOS_SETUP_COMPLETE,
+                                     Bind(&impl::on_qos_setup_complete, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::ROLE_CHANGE, Bind(&impl::on_role_change, common::Unretained(this)),
+                                     handler_);
+    hci_layer_->RegisterEventHandler(EventCode::FLOW_SPECIFICATION_COMPLETE,
+                                     Bind(&impl::on_flow_specification_complete, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::FLUSH_OCCURRED,
+                                     Bind(&impl::on_flush_occurred, common::Unretained(this)), handler_);
+    hci_mtu_ = controller_->GetControllerAclPacketLength();
   }
 
   void Stop() {
     hci_layer_->UnregisterEventHandler(EventCode::DISCONNECTION_COMPLETE);
     hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_COMPLETE);
     hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_REQUEST);
+    hci_layer_->UnregisterEventHandler(EventCode::AUTHENTICATION_COMPLETE);
     hci_queue_end_->UnregisterDequeue();
     unregister_all_connections();
     acl_connections_.clear();
@@ -138,20 +170,27 @@
 
   void buffer_packet() {
     unregister_all_connections();
-    PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
     BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
     //   Wrap packet and enqueue it
     uint16_t handle = current_connection_pair_->first;
-    packet_to_send_ = AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag,
-                                               current_connection_pair_->second.queue_->GetDownEnd()->TryDequeue());
-    ASSERT(packet_to_send_ != nullptr);
-    fragment_and_send();
-  }
 
-  void fragment_and_send() {
-    // TODO: Fragment the packet into a list of packets
-    fragments_to_send_.push_back(std::move(packet_to_send_));
-    packet_to_send_ = nullptr;
+    auto packet = current_connection_pair_->second.queue_->GetDownEnd()->TryDequeue();
+    ASSERT(packet != nullptr);
+
+    if (packet->size() <= hci_mtu_) {
+      fragments_to_send_.push_front(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE,
+                                                             broadcast_flag, std::move(packet)));
+    } else {
+      auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments();
+      PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+      for (size_t i = 0; i < fragments.size(); i++) {
+        fragments_to_send_.push_back(
+            AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i])));
+        packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
+      }
+    }
+    ASSERT(fragments_to_send_.size() > 0);
+
     current_connection_pair_->second.number_of_sent_packets_ += fragments_to_send_.size();
     send_next_fragment();
   }
@@ -184,6 +223,9 @@
       return;
     }
     uint16_t handle = packet->GetHandle();
+    if (handle == kQualcommDebugHandle) {
+      return;
+    }
     auto connection_pair = acl_connections_.find(handle);
     if (connection_pair == acl_connections_.end()) {
       LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), handle);
@@ -204,7 +246,7 @@
   void on_incoming_connection(EventPacketView packet) {
     ConnectionRequestView request = ConnectionRequestView::Create(packet);
     ASSERT(request.IsValid());
-    common::Address address = request.GetBdAddr();
+    Address address = request.GetBdAddr();
     if (client_callbacks_ == nullptr) {
       LOG_ERROR("No callbacks to call");
       auto reason = RejectConnectionReason::LIMITED_RESOURCES;
@@ -212,7 +254,10 @@
       return;
     }
     connecting_.insert(address);
-    if (should_accept_connection_.Run(address, request.GetClassOfDevice())) {
+    if (is_classic_link_already_connected(address)) {
+      auto reason = RejectConnectionReason::UNACCEPTABLE_BD_ADDR;
+      this->reject_connection(RejectConnectionRequestBuilder::Create(address, reason));
+    } else if (should_accept_connection_.Run(address, request.GetClassOfDevice())) {
       this->accept_connection(address);
     } else {
       auto reason = RejectConnectionReason::LIMITED_RESOURCES;  // TODO: determine reason
@@ -220,35 +265,124 @@
     }
   }
 
-  void on_connection_complete(EventPacketView packet) {
-    ConnectionCompleteView connection_complete = ConnectionCompleteView::Create(std::move(packet));
-    ASSERT(connection_complete.IsValid());
-    auto status = connection_complete.GetStatus();
-    auto address = connection_complete.GetBdAddr();
+  void on_classic_connection_complete(Address address) {
     auto connecting_addr = connecting_.find(address);
     if (connecting_addr == connecting_.end()) {
       LOG_WARN("No prior connection request for %s", address.ToString().c_str());
     } else {
       connecting_.erase(connecting_addr);
     }
-    if (status == ErrorCode::SUCCESS) {
-      uint16_t handle = connection_complete.GetConnectionHandle();
-      ASSERT(acl_connections_.count(handle) == 0);
-      acl_connections_[handle] = {};
-      if (acl_connections_.size() == 1 && packet_to_send_ == nullptr) {
-        start_round_robin();
-      }
-      AclConnection connection_proxy{&acl_manager_, handle, address};
-      client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess,
-                                             common::Unretained(client_callbacks_), std::move(connection_proxy)));
+  }
+
+  void on_common_le_connection_complete(AddressWithType address_with_type) {
+    auto connecting_addr_with_type = connecting_le_.find(address_with_type);
+    if (connecting_addr_with_type == connecting_le_.end()) {
+      LOG_WARN("No prior connection request for %s", address_with_type.ToString().c_str());
     } else {
+      connecting_le_.erase(connecting_addr_with_type);
+    }
+  }
+
+  void on_le_connection_complete(LeMetaEventView packet) {
+    LeConnectionCompleteView connection_complete = LeConnectionCompleteView::Create(packet);
+    ASSERT(connection_complete.IsValid());
+    auto status = connection_complete.GetStatus();
+    auto address = connection_complete.GetPeerAddress();
+    auto peer_address_type = connection_complete.GetPeerAddressType();
+    // TODO: find out which address and type was used to initiate the connection
+    AddressWithType address_with_type(address, peer_address_type);
+    on_common_le_connection_complete(address_with_type);
+    if (status != ErrorCode::SUCCESS) {
+      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
+                                                common::Unretained(le_client_callbacks_), address_with_type, status));
+      return;
+    }
+    // TODO: Check and save other connection parameters
+    uint16_t handle = connection_complete.GetConnectionHandle();
+    ASSERT(acl_connections_.count(handle) == 0);
+    acl_connections_.emplace(handle, address_with_type);
+    if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+      start_round_robin();
+    }
+    auto role = connection_complete.GetRole();
+    std::unique_ptr<AclConnection> connection_proxy(
+        new AclConnection(&acl_manager_, handle, address, peer_address_type, role));
+    le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(le_client_callbacks_), address_with_type,
+                                              std::move(connection_proxy)));
+  }
+
+  void on_le_enhanced_connection_complete(LeMetaEventView packet) {
+    LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet);
+    ASSERT(connection_complete.IsValid());
+    auto status = connection_complete.GetStatus();
+    auto address = connection_complete.GetPeerAddress();
+    auto peer_address_type = connection_complete.GetPeerAddressType();
+    auto peer_resolvable_address = connection_complete.GetPeerResolvablePrivateAddress();
+    AddressWithType reporting_address_with_type(address, peer_address_type);
+    if (!peer_resolvable_address.IsEmpty()) {
+      reporting_address_with_type = AddressWithType(peer_resolvable_address, AddressType::RANDOM_DEVICE_ADDRESS);
+    }
+    on_common_le_connection_complete(reporting_address_with_type);
+    if (status != ErrorCode::SUCCESS) {
+      le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
+                                                common::Unretained(le_client_callbacks_), reporting_address_with_type,
+                                                status));
+      return;
+    }
+    // TODO: Check and save other connection parameters
+    uint16_t handle = connection_complete.GetConnectionHandle();
+    ASSERT(acl_connections_.count(handle) == 0);
+    acl_connections_.emplace(handle, reporting_address_with_type);
+    if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+      start_round_robin();
+    }
+    auto role = connection_complete.GetRole();
+    std::unique_ptr<AclConnection> connection_proxy(
+        new AclConnection(&acl_manager_, handle, address, peer_address_type, role));
+    le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(le_client_callbacks_), reporting_address_with_type,
+                                              std::move(connection_proxy)));
+  }
+
+  void on_connection_complete(EventPacketView packet) {
+    ConnectionCompleteView connection_complete = ConnectionCompleteView::Create(packet);
+    ASSERT(connection_complete.IsValid());
+    auto status = connection_complete.GetStatus();
+    auto address = connection_complete.GetBdAddr();
+    on_classic_connection_complete(address);
+    if (status != ErrorCode::SUCCESS) {
       client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectFail, common::Unretained(client_callbacks_),
                                              address, status));
+      return;
+    }
+    uint16_t handle = connection_complete.GetConnectionHandle();
+    ASSERT(acl_connections_.count(handle) == 0);
+    acl_connections_.emplace(handle, AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS});
+    if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+      start_round_robin();
+    }
+    std::unique_ptr<AclConnection> connection_proxy(new AclConnection(&acl_manager_, handle, address));
+    client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess,
+                                           common::Unretained(client_callbacks_), std::move(connection_proxy)));
+    while (!pending_outgoing_connections_.empty()) {
+      auto create_connection_packet_and_address = std::move(pending_outgoing_connections_.front());
+      pending_outgoing_connections_.pop();
+      if (!is_classic_link_already_connected(create_connection_packet_and_address.first)) {
+        connecting_.insert(create_connection_packet_and_address.first);
+        hci_layer_->EnqueueCommand(std::move(create_connection_packet_and_address.second),
+                                   common::BindOnce([](CommandStatusView status) {
+                                     ASSERT(status.IsValid());
+                                     ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+                                   }),
+                                   handler_);
+        break;
+      }
     }
   }
 
   void on_disconnection_complete(EventPacketView packet) {
-    DisconnectionCompleteView disconnection_complete = DisconnectionCompleteView::Create(std::move(packet));
+    DisconnectionCompleteView disconnection_complete = DisconnectionCompleteView::Create(packet);
     ASSERT(disconnection_complete.IsValid());
     uint16_t handle = disconnection_complete.GetConnectionHandle();
     auto status = disconnection_complete.GetStatus();
@@ -267,7 +401,479 @@
     }
   }
 
-  void create_connection(common::Address address) {
+  void on_connection_packet_type_changed(EventPacketView packet) {
+    ConnectionPacketTypeChangedView packet_type_changed = ConnectionPacketTypeChangedView::Create(packet);
+    if (!packet_type_changed.IsValid()) {
+      LOG_ERROR("Received on_connection_packet_type_changed with invalid packet");
+      return;
+    } else if (packet_type_changed.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = packet_type_changed.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_connection_packet_type_changed with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = packet_type_changed.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t packet_type = packet_type_changed.GetPacketType();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnConnectionPacketTypeChanged,
+                           common::Unretained(acl_connection.command_complete_callbacks_), packet_type));
+    }
+  }
+
+  void on_master_link_key_complete(EventPacketView packet) {
+    MasterLinkKeyCompleteView complete_view = MasterLinkKeyCompleteView::Create(packet);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_master_link_key_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_master_link_key_complete with error code %s", error_code.c_str());
+      return;
+    }
+    if (acl_manager_client_callbacks_ != nullptr) {
+      uint16_t connection_handle = complete_view.GetConnectionHandle();
+      KeyFlag key_flag = complete_view.GetKeyFlag();
+      acl_manager_client_handler_->Post(common::BindOnce(&AclManagerCallbacks::OnMasterLinkKeyComplete,
+                                                         common::Unretained(acl_manager_client_callbacks_),
+                                                         connection_handle, key_flag));
+    }
+  }
+
+  void on_authentication_complete(EventPacketView packet) {
+    AuthenticationCompleteView authentication_complete = AuthenticationCompleteView::Create(packet);
+    if (!authentication_complete.IsValid()) {
+      LOG_ERROR("Received on_authentication_complete with invalid packet");
+      return;
+    } else if (authentication_complete.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = authentication_complete.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_authentication_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = authentication_complete.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnAuthenticationComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_)));
+    }
+  }
+
+  void on_encryption_change(EventPacketView packet) {
+    EncryptionChangeView encryption_change_view = EncryptionChangeView::Create(packet);
+    if (!encryption_change_view.IsValid()) {
+      LOG_ERROR("Received on_encryption_change with invalid packet");
+      return;
+    } else if (encryption_change_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = encryption_change_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_change_connection_link_key_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = encryption_change_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      EncryptionEnabled enabled = encryption_change_view.GetEncryptionEnabled();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnEncryptionChange,
+                           common::Unretained(acl_connection.command_complete_callbacks_), enabled));
+    }
+  }
+
+  void on_change_connection_link_key_complete(EventPacketView packet) {
+    ChangeConnectionLinkKeyCompleteView complete_view = ChangeConnectionLinkKeyCompleteView::Create(packet);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_change_connection_link_key_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_change_connection_link_key_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnChangeConnectionLinkKeyComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_)));
+    }
+  }
+
+  void on_read_clock_offset_complete(EventPacketView packet) {
+    ReadClockOffsetCompleteView complete_view = ReadClockOffsetCompleteView::Create(packet);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_clock_offset_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_clock_offset_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t clock_offset = complete_view.GetClockOffset();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadClockOffsetComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), clock_offset));
+    }
+  }
+
+  void on_mode_change(EventPacketView packet) {
+    ModeChangeView mode_change_view = ModeChangeView::Create(packet);
+    if (!mode_change_view.IsValid()) {
+      LOG_ERROR("Received on_mode_change with invalid packet");
+      return;
+    } else if (mode_change_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = mode_change_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_mode_change with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = mode_change_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      Mode current_mode = mode_change_view.GetCurrentMode();
+      uint16_t interval = mode_change_view.GetInterval();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnModeChange,
+                           common::Unretained(acl_connection.command_complete_callbacks_), current_mode, interval));
+    }
+  }
+
+  void on_qos_setup_complete(EventPacketView packet) {
+    QosSetupCompleteView complete_view = QosSetupCompleteView::Create(packet);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_qos_setup_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_qos_setup_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      ServiceType service_type = complete_view.GetServiceType();
+      uint32_t token_rate = complete_view.GetTokenRate();
+      uint32_t peak_bandwidth = complete_view.GetPeakBandwidth();
+      uint32_t latency = complete_view.GetLatency();
+      uint32_t delay_variation = complete_view.GetDelayVariation();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnQosSetupComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), service_type, token_rate,
+                           peak_bandwidth, latency, delay_variation));
+    }
+  }
+
+  void on_role_change(EventPacketView packet) {
+    RoleChangeView role_change_view = RoleChangeView::Create(packet);
+    if (!role_change_view.IsValid()) {
+      LOG_ERROR("Received on_role_change with invalid packet");
+      return;
+    } else if (role_change_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = role_change_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_role_change with error code %s", error_code.c_str());
+      return;
+    }
+    if (acl_manager_client_callbacks_ != nullptr) {
+      Address bd_addr = role_change_view.GetBdAddr();
+      Role new_role = role_change_view.GetNewRole();
+      acl_manager_client_handler_->Post(common::BindOnce(
+          &AclManagerCallbacks::OnRoleChange, common::Unretained(acl_manager_client_callbacks_), bd_addr, new_role));
+    }
+  }
+
+  void on_flow_specification_complete(EventPacketView packet) {
+    FlowSpecificationCompleteView complete_view = FlowSpecificationCompleteView::Create(packet);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_flow_specification_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_flow_specification_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      FlowDirection flow_direction = complete_view.GetFlowDirection();
+      ServiceType service_type = complete_view.GetServiceType();
+      uint32_t token_rate = complete_view.GetTokenRate();
+      uint32_t token_bucket_size = complete_view.GetTokenBucketSize();
+      uint32_t peak_bandwidth = complete_view.GetPeakBandwidth();
+      uint32_t access_latency = complete_view.GetAccessLatency();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnFlowSpecificationComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), flow_direction, service_type,
+                           token_rate, token_bucket_size, peak_bandwidth, access_latency));
+    }
+  }
+
+  void on_flush_occurred(EventPacketView packet) {
+    FlushOccurredView flush_occurred_view = FlushOccurredView::Create(packet);
+    if (!flush_occurred_view.IsValid()) {
+      LOG_ERROR("Received on_flush_occurred with invalid packet");
+      return;
+    }
+    uint16_t handle = flush_occurred_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnFlushOccurred,
+                           common::Unretained(acl_connection.command_complete_callbacks_)));
+    }
+  }
+
+  void on_role_discovery_complete(CommandCompleteView view) {
+    auto complete_view = RoleDiscoveryCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_role_discovery_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_role_discovery_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      Role role = complete_view.GetCurrentRole();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnRoleDiscoveryComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), role));
+    }
+  }
+
+  void on_read_link_policy_settings_complete(CommandCompleteView view) {
+    auto complete_view = ReadLinkPolicySettingsCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_link_policy_settings_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_link_policy_settings_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t link_policy_settings = complete_view.GetLinkPolicySettings();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkPolicySettingsComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), link_policy_settings));
+    }
+  }
+
+  void on_read_default_link_policy_settings_complete(CommandCompleteView view) {
+    auto complete_view = ReadDefaultLinkPolicySettingsCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_link_policy_settings_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_link_policy_settings_complete with error code %s", error_code.c_str());
+      return;
+    }
+    if (acl_manager_client_callbacks_ != nullptr) {
+      uint16_t default_link_policy_settings = complete_view.GetDefaultLinkPolicySettings();
+      acl_manager_client_handler_->Post(common::BindOnce(&AclManagerCallbacks::OnReadDefaultLinkPolicySettingsComplete,
+                                                         common::Unretained(acl_manager_client_callbacks_),
+                                                         default_link_policy_settings));
+    }
+  }
+
+  void on_read_automatic_flush_timeout_complete(CommandCompleteView view) {
+    auto complete_view = ReadAutomaticFlushTimeoutCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_automatic_flush_timeout_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_automatic_flush_timeout_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t flush_timeout = complete_view.GetFlushTimeout();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadAutomaticFlushTimeoutComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), flush_timeout));
+    }
+  }
+
+  void on_read_transmit_power_level_complete(CommandCompleteView view) {
+    auto complete_view = ReadTransmitPowerLevelCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_transmit_power_level_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_transmit_power_level_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint8_t transmit_power_level = complete_view.GetTransmitPowerLevel();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadTransmitPowerLevelComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), transmit_power_level));
+    }
+  }
+
+  void on_read_link_supervision_timeout_complete(CommandCompleteView view) {
+    auto complete_view = ReadLinkSupervisionTimeoutCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_link_supervision_timeout_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_link_supervision_timeout_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t link_supervision_timeout = complete_view.GetLinkSupervisionTimeout();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkSupervisionTimeoutComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), link_supervision_timeout));
+    }
+  }
+
+  void on_read_failed_contact_counter_complete(CommandCompleteView view) {
+    auto complete_view = ReadFailedContactCounterCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_failed_contact_counter_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_failed_contact_counter_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint16_t failed_contact_counter = complete_view.GetFailedContactCounter();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadFailedContactCounterComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), failed_contact_counter));
+    }
+  }
+
+  void on_read_link_quality_complete(CommandCompleteView view) {
+    auto complete_view = ReadLinkQualityCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_link_quality_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_link_quality_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint8_t link_quality = complete_view.GetLinkQuality();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkQualityComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), link_quality));
+    }
+  }
+
+  void on_read_afh_channel_map_complete(CommandCompleteView view) {
+    auto complete_view = ReadAfhChannelMapCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_afh_channel_map_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_afh_channel_map_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      AfhMode afh_mode = complete_view.GetAfhMode();
+      std::array<uint8_t, 10> afh_channel_map = complete_view.GetAfhChannelMap();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadAfhChannelMapComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), afh_mode, afh_channel_map));
+    }
+  }
+
+  void on_read_rssi_complete(CommandCompleteView view) {
+    auto complete_view = ReadRssiCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_rssi_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_rssi_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint8_t rssi = complete_view.GetRssi();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadRssiComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), rssi));
+    }
+  }
+
+  void on_read_clock_complete(CommandCompleteView view) {
+    auto complete_view = ReadClockCompleteView::Create(view);
+    if (!complete_view.IsValid()) {
+      LOG_ERROR("Received on_read_clock_complete with invalid packet");
+      return;
+    } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+      auto status = complete_view.GetStatus();
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received on_read_clock_complete with error code %s", error_code.c_str());
+      return;
+    }
+    uint16_t handle = complete_view.GetConnectionHandle();
+    auto& acl_connection = acl_connections_.find(handle)->second;
+    if (acl_connection.command_complete_handler_ != nullptr) {
+      uint32_t clock = complete_view.GetClock();
+      uint16_t accuracy = complete_view.GetAccuracy();
+      acl_connection.command_complete_handler_->Post(
+          common::BindOnce(&ConnectionManagementCallbacks::OnReadClockComplete,
+                           common::Unretained(acl_connection.command_complete_callbacks_), clock, accuracy));
+    }
+  }
+
+  bool is_classic_link_already_connected(Address address) {
+    for (const auto& connection : acl_connections_) {
+      if (connection.second.address_with_type_.GetAddress() == address) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void create_connection(Address address) {
     // TODO: Configure default connection parameters?
     uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
     PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R1;
@@ -275,31 +881,97 @@
     ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
     CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
     ASSERT(client_callbacks_ != nullptr);
-
-    connecting_.insert(address);
     std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
         address, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);
 
-    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
-                                 ASSERT(status.IsValid());
-                                 ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
-                               }),
-                               handler_);
+    if (connecting_.empty()) {
+      if (is_classic_link_already_connected(address)) {
+        LOG_WARN("already connected: %s", address.ToString().c_str());
+        return;
+      }
+      connecting_.insert(address);
+      hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
+                                   ASSERT(status.IsValid());
+                                   ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+                                 }),
+                                 handler_);
+    } else {
+      pending_outgoing_connections_.emplace(address, std::move(packet));
+    }
   }
 
-  void cancel_connect(common::Address address) {
+  void create_le_connection(AddressWithType address_with_type) {
+    // TODO: Add white list handling.
+    // TODO: Configure default LE connection parameters?
+    uint16_t le_scan_interval = 0x0020;
+    uint16_t le_scan_window = 0x0010;
+    InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_PEER_ADDRESS;
+    OwnAddressType own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS;
+    uint16_t conn_interval_min = 0x0006;
+    uint16_t conn_interval_max = 0x0C00;
+    uint16_t conn_latency = 0x0C0;
+    uint16_t supervision_timeout = 0x0C00;
+    uint16_t minimum_ce_length = 0x0002;
+    uint16_t maximum_ce_length = 0x0C00;
+    ASSERT(le_client_callbacks_ != nullptr);
+
+    connecting_le_.insert(address_with_type);
+
+    hci_layer_->EnqueueCommand(
+        LeCreateConnectionBuilder::Create(le_scan_interval, le_scan_window, initiator_filter_policy,
+                                          address_with_type.GetAddressType(), address_with_type.GetAddress(),
+                                          own_address_type, conn_interval_min, conn_interval_max, conn_latency,
+                                          supervision_timeout, minimum_ce_length, maximum_ce_length),
+        common::BindOnce([](CommandStatusView status) {
+          ASSERT(status.IsValid());
+          ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+        }),
+        handler_);
+  }
+
+  void cancel_connect(Address address) {
     auto connecting_addr = connecting_.find(address);
     if (connecting_addr == connecting_.end()) {
       LOG_INFO("Cannot cancel non-existent connection to %s", address.ToString().c_str());
       return;
     }
-    connecting_.erase(connecting_addr);
     std::unique_ptr<CreateConnectionCancelBuilder> packet = CreateConnectionCancelBuilder::Create(address);
     hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandCompleteView complete) { /* TODO */ }),
                                handler_);
   }
 
-  void accept_connection(common::Address address) {
+  void master_link_key(KeyFlag key_flag) {
+    std::unique_ptr<MasterLinkKeyBuilder> packet = MasterLinkKeyBuilder::Create(key_flag);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        common::BindOnce(&impl::check_command_status<MasterLinkKeyStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void switch_role(Address address, Role role) {
+    std::unique_ptr<SwitchRoleBuilder> packet = SwitchRoleBuilder::Create(address, role);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        common::BindOnce(&impl::check_command_status<SwitchRoleStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void read_default_link_policy_settings() {
+    std::unique_ptr<ReadDefaultLinkPolicySettingsBuilder> packet = ReadDefaultLinkPolicySettingsBuilder::Create();
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        common::BindOnce(&impl::on_read_default_link_policy_settings_complete, common::Unretained(this)), handler_);
+  }
+
+  void write_default_link_policy_settings(uint16_t default_link_policy_settings) {
+    std::unique_ptr<WriteDefaultLinkPolicySettingsBuilder> packet =
+        WriteDefaultLinkPolicySettingsBuilder::Create(default_link_policy_settings);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_complete<WriteDefaultLinkPolicySettingsCompleteView>,
+                 common::Unretained(this)),
+        handler_);
+  }
+
+  void accept_connection(Address address) {
     auto role = AcceptConnectionRequestRole::BECOME_MASTER;  // We prefer to be master
     hci_layer_->EnqueueCommand(AcceptConnectionRequestBuilder::Create(address, role),
                                common::BindOnce(&impl::on_accept_connection_status, common::Unretained(this), address),
@@ -313,6 +985,243 @@
                                handler_);
   }
 
+  void handle_change_connection_packet_type(uint16_t handle, uint16_t packet_type) {
+    ASSERT(acl_connections_.count(handle) == 1);
+    std::unique_ptr<ChangeConnectionPacketTypeBuilder> packet =
+        ChangeConnectionPacketTypeBuilder::Create(handle, packet_type);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               BindOnce(&AclManager::impl::check_command_status<ChangeConnectionPacketTypeStatusView>,
+                                        common::Unretained(this)),
+                               handler_);
+  }
+
+  void handle_authentication_requested(uint16_t handle) {
+    std::unique_ptr<AuthenticationRequestedBuilder> packet = AuthenticationRequestedBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<AuthenticationRequestedStatusView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_set_connection_encryption(uint16_t handle, Enable enable) {
+    std::unique_ptr<SetConnectionEncryptionBuilder> packet = SetConnectionEncryptionBuilder::Create(handle, enable);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<SetConnectionEncryptionStatusView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_change_connection_link_key(uint16_t handle) {
+    std::unique_ptr<ChangeConnectionLinkKeyBuilder> packet = ChangeConnectionLinkKeyBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<ChangeConnectionLinkKeyStatusView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_read_clock_offset(uint16_t handle) {
+    std::unique_ptr<ReadClockOffsetBuilder> packet = ReadClockOffsetBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<ReadClockOffsetStatusView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_hold_mode(uint16_t handle, uint16_t max_interval, uint16_t min_interval) {
+    std::unique_ptr<HoldModeBuilder> packet = HoldModeBuilder::Create(handle, max_interval, min_interval);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<HoldModeStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void handle_sniff_mode(uint16_t handle, uint16_t max_interval, uint16_t min_interval, int16_t attempt,
+                         uint16_t timeout) {
+    std::unique_ptr<SniffModeBuilder> packet =
+        SniffModeBuilder::Create(handle, max_interval, min_interval, attempt, timeout);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<SniffModeStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void handle_exit_sniff_mode(uint16_t handle) {
+    std::unique_ptr<ExitSniffModeBuilder> packet = ExitSniffModeBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<ExitSniffModeStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void handle_qos_setup_mode(uint16_t handle, ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+                             uint32_t latency, uint32_t delay_variation) {
+    std::unique_ptr<QosSetupBuilder> packet =
+        QosSetupBuilder::Create(handle, service_type, token_rate, peak_bandwidth, latency, delay_variation);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<QosSetupStatusView>, common::Unretained(this)), handler_);
+  }
+
+  void handle_role_discovery(uint16_t handle) {
+    std::unique_ptr<RoleDiscoveryBuilder> packet = RoleDiscoveryBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_role_discovery_complete, common::Unretained(this)), handler_);
+  }
+
+  void handle_read_link_policy_settings(uint16_t handle) {
+    std::unique_ptr<ReadLinkPolicySettingsBuilder> packet = ReadLinkPolicySettingsBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_read_link_policy_settings_complete, common::Unretained(this)),
+                               handler_);
+  }
+
+  void handle_write_link_policy_settings(uint16_t handle, uint16_t link_policy_settings) {
+    std::unique_ptr<WriteLinkPolicySettingsBuilder> packet =
+        WriteLinkPolicySettingsBuilder::Create(handle, link_policy_settings);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               BindOnce(&AclManager::impl::check_command_complete<WriteLinkPolicySettingsCompleteView>,
+                                        common::Unretained(this)),
+                               handler_);
+  }
+
+  void handle_flow_specification(uint16_t handle, FlowDirection flow_direction, ServiceType service_type,
+                                 uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth,
+                                 uint32_t access_latency) {
+    std::unique_ptr<FlowSpecificationBuilder> packet = FlowSpecificationBuilder::Create(
+        handle, flow_direction, service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_status<FlowSpecificationStatusView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_sniff_subrating(uint16_t handle, uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+                              uint16_t minimum_local_timeout) {
+    std::unique_ptr<SniffSubratingBuilder> packet =
+        SniffSubratingBuilder::Create(handle, maximum_latency, minimum_remote_timeout, minimum_local_timeout);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_complete<SniffSubratingCompleteView>, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_flush(uint16_t handle) {
+    std::unique_ptr<FlushBuilder> packet = FlushBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_complete<FlushCompleteView>, common::Unretained(this)), handler_);
+  }
+
+  void handle_read_automatic_flush_timeout(uint16_t handle) {
+    std::unique_ptr<ReadAutomaticFlushTimeoutBuilder> packet = ReadAutomaticFlushTimeoutBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet), common::BindOnce(&impl::on_read_automatic_flush_timeout_complete, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_write_automatic_flush_timeout(uint16_t handle, uint16_t flush_timeout) {
+    std::unique_ptr<WriteAutomaticFlushTimeoutBuilder> packet =
+        WriteAutomaticFlushTimeoutBuilder::Create(handle, flush_timeout);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_complete<WriteAutomaticFlushTimeoutCompleteView>,
+                 common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_read_transmit_power_level(uint16_t handle, TransmitPowerLevelType type) {
+    std::unique_ptr<ReadTransmitPowerLevelBuilder> packet = ReadTransmitPowerLevelBuilder::Create(handle, type);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_read_transmit_power_level_complete, common::Unretained(this)),
+                               handler_);
+  }
+
+  void handle_read_link_supervision_timeout(uint16_t handle) {
+    std::unique_ptr<ReadLinkSupervisionTimeoutBuilder> packet = ReadLinkSupervisionTimeoutBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet), common::BindOnce(&impl::on_read_link_supervision_timeout_complete, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_write_link_supervision_timeout(uint16_t handle, uint16_t link_supervision_timeout) {
+    std::unique_ptr<WriteLinkSupervisionTimeoutBuilder> packet =
+        WriteLinkSupervisionTimeoutBuilder::Create(handle, link_supervision_timeout);
+    hci_layer_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&AclManager::impl::check_command_complete<WriteLinkSupervisionTimeoutCompleteView>,
+                 common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_read_failed_contact_counter(uint16_t handle) {
+    std::unique_ptr<ReadFailedContactCounterBuilder> packet = ReadFailedContactCounterBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet), common::BindOnce(&impl::on_read_failed_contact_counter_complete, common::Unretained(this)),
+        handler_);
+  }
+
+  void handle_reset_failed_contact_counter(uint16_t handle) {
+    std::unique_ptr<ResetFailedContactCounterBuilder> packet = ResetFailedContactCounterBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(std::move(packet), BindOnce([](CommandCompleteView view) { /* TODO: check? */ }),
+                               handler_);
+  }
+
+  void handle_read_link_quality(uint16_t handle) {
+    std::unique_ptr<ReadLinkQualityBuilder> packet = ReadLinkQualityBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(
+        std::move(packet), common::BindOnce(&impl::on_read_link_quality_complete, common::Unretained(this)), handler_);
+  }
+
+  void handle_afh_channel_map(uint16_t handle) {
+    std::unique_ptr<ReadAfhChannelMapBuilder> packet = ReadAfhChannelMapBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_read_afh_channel_map_complete, common::Unretained(this)),
+                               handler_);
+  }
+
+  void handle_read_rssi(uint16_t handle) {
+    std::unique_ptr<ReadRssiBuilder> packet = ReadRssiBuilder::Create(handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_read_rssi_complete, common::Unretained(this)), handler_);
+  }
+
+  void handle_read_clock(uint16_t handle, WhichClock which_clock) {
+    std::unique_ptr<ReadClockBuilder> packet = ReadClockBuilder::Create(handle, which_clock);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_read_clock_complete, common::Unretained(this)), handler_);
+  }
+
+  template <class T>
+  void check_command_complete(CommandCompleteView view) {
+    ASSERT(view.IsValid());
+    auto status_view = T::Create(view);
+    if (!status_view.IsValid()) {
+      LOG_ERROR("Received command complete with invalid packet, opcode 0x%02hx", view.GetCommandOpCode());
+      return;
+    }
+    ErrorCode status = status_view.GetStatus();
+    OpCode op_code = status_view.GetCommandOpCode();
+    if (status != ErrorCode::SUCCESS) {
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received command complete with error code %s, opcode 0x%02hx", error_code.c_str(), op_code);
+      return;
+    }
+  }
+
+  template <class T>
+  void check_command_status(CommandStatusView view) {
+    ASSERT(view.IsValid());
+    auto status_view = T::Create(view);
+    if (!status_view.IsValid()) {
+      LOG_ERROR("Received command status with invalid packet, opcode 0x%02hx", view.GetCommandOpCode());
+      return;
+    }
+    ErrorCode status = status_view.GetStatus();
+    OpCode op_code = status_view.GetCommandOpCode();
+    if (status != ErrorCode::SUCCESS) {
+      std::string error_code = ErrorCodeText(status);
+      LOG_ERROR("Received command status with error code %s, opcode 0x%02hx", error_code.c_str(), op_code);
+      return;
+    }
+  }
+
   void cleanup(uint16_t handle) {
     ASSERT(acl_connections_.count(handle) == 1);
     auto& acl_connection = acl_connections_.find(handle)->second;
@@ -323,7 +1232,7 @@
     acl_connections_.erase(handle);
   }
 
-  void on_accept_connection_status(common::Address address, CommandStatusView status) {
+  void on_accept_connection_status(Address address, CommandStatusView status) {
     auto accept_status = AcceptConnectionRequestStatusView::Create(status);
     ASSERT(accept_status.IsValid());
     if (status.GetStatus() != ErrorCode::SUCCESS) {
@@ -343,6 +1252,20 @@
     client_handler_ = handler;
   }
 
+  void handle_register_le_callbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
+    ASSERT(le_client_callbacks_ == nullptr);
+    ASSERT(le_client_handler_ == nullptr);
+    le_client_callbacks_ = callbacks;
+    le_client_handler_ = handler;
+  }
+
+  void handle_register_acl_manager_callbacks(AclManagerCallbacks* callbacks, os::Handler* handler) {
+    ASSERT(acl_manager_client_callbacks_ == nullptr);
+    ASSERT(acl_manager_client_handler_ == nullptr);
+    acl_manager_client_callbacks_ = callbacks;
+    acl_manager_client_handler_ = handler;
+  }
+
   acl_connection& check_and_get_connection(uint16_t handle) {
     auto connection = acl_connections_.find(handle);
     ASSERT(connection != acl_connections_.end());
@@ -351,10 +1274,15 @@
 
   AclConnection::QueueUpEnd* get_acl_queue_end(uint16_t handle) {
     auto& connection = check_and_get_connection(handle);
-    ASSERT_LOG(connection.disconnect_handler_ != nullptr, "No disconnect handler registered.");
     return connection.queue_->GetUpEnd();
   }
 
+  void RegisterCallbacks(uint16_t handle, ConnectionManagementCallbacks* callbacks, os::Handler* handler) {
+    auto& connection = check_and_get_connection(handle);
+    connection.command_complete_callbacks_ = callbacks;
+    connection.command_complete_handler_ = handler;
+  }
+
   void RegisterDisconnectCallback(uint16_t handle, common::OnceCallback<void(ErrorCode)> on_disconnect,
                                   os::Handler* handler) {
     auto& connection = check_and_get_connection(handle);
@@ -375,20 +1303,290 @@
     return true;
   }
 
+  bool ChangeConnectionPacketType(uint16_t handle, uint16_t packet_type) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(
+        BindOnce(&impl::handle_change_connection_packet_type, common::Unretained(this), handle, packet_type));
+    return true;
+  }
+
+  bool AuthenticationRequested(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_authentication_requested, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool SetConnectionEncryption(uint16_t handle, Enable enable) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_set_connection_encryption, common::Unretained(this), handle, enable));
+    return true;
+  }
+
+  bool ChangeConnectionLinkKey(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_change_connection_link_key, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadClockOffset(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_clock_offset, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool HoldMode(uint16_t handle, uint16_t max_interval, uint16_t min_interval) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_hold_mode, common::Unretained(this), handle, max_interval, min_interval));
+    return true;
+  }
+
+  bool SniffMode(uint16_t handle, uint16_t max_interval, uint16_t min_interval, int16_t attempt, uint16_t timeout) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_sniff_mode, common::Unretained(this), handle, max_interval, min_interval,
+                            attempt, timeout));
+    return true;
+  }
+
+  bool ExitSniffMode(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_exit_sniff_mode, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool QosSetup(uint16_t handle, ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+                uint32_t latency, uint32_t delay_variation) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_qos_setup_mode, common::Unretained(this), handle, service_type, token_rate,
+                            peak_bandwidth, latency, delay_variation));
+    return true;
+  }
+
+  bool RoleDiscovery(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_role_discovery, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadLinkPolicySettings(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_link_policy_settings, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool WriteLinkPolicySettings(uint16_t handle, uint16_t link_policy_settings) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(
+        BindOnce(&impl::handle_write_link_policy_settings, common::Unretained(this), handle, link_policy_settings));
+    return true;
+  }
+
+  bool FlowSpecification(uint16_t handle, FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                         uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_flow_specification, common::Unretained(this), handle, flow_direction,
+                            service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency));
+    return true;
+  }
+
+  bool SniffSubrating(uint16_t handle, uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+                      uint16_t minimum_local_timeout) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_sniff_subrating, common::Unretained(this), handle, maximum_latency,
+                            minimum_remote_timeout, minimum_local_timeout));
+    return true;
+  }
+
+  bool Flush(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_flush, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadAutomaticFlushTimeout(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_automatic_flush_timeout, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool WriteAutomaticFlushTimeout(uint16_t handle, uint16_t flush_timeout) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(
+        BindOnce(&impl::handle_write_automatic_flush_timeout, common::Unretained(this), handle, flush_timeout));
+    return true;
+  }
+
+  bool ReadTransmitPowerLevel(uint16_t handle, TransmitPowerLevelType type) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_transmit_power_level, common::Unretained(this), handle, type));
+    return true;
+  }
+
+  bool ReadLinkSupervisionTimeout(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_link_supervision_timeout, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool WriteLinkSupervisionTimeout(uint16_t handle, uint16_t link_supervision_timeout) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_write_link_supervision_timeout, common::Unretained(this), handle,
+                            link_supervision_timeout));
+    return true;
+  }
+
+  bool ReadFailedContactCounter(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_failed_contact_counter, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ResetFailedContactCounter(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_reset_failed_contact_counter, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadLinkQuality(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_link_quality, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadAfhChannelMap(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_afh_channel_map, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadRssi(uint16_t handle) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_rssi, common::Unretained(this), handle));
+    return true;
+  }
+
+  bool ReadClock(uint16_t handle, WhichClock which_clock) {
+    auto& connection = check_and_get_connection(handle);
+    if (connection.is_disconnected_) {
+      LOG_INFO("Already disconnected");
+      return false;
+    }
+    handler_->Post(BindOnce(&impl::handle_read_clock, common::Unretained(this), handle, which_clock));
+    return true;
+  }
+
   void Finish(uint16_t handle) {
     auto& connection = check_and_get_connection(handle);
     ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle);
     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;
   uint16_t acl_packet_credits_ = 0;
   uint16_t acl_buffer_length_ = 0;
 
-  std::unique_ptr<AclPacketBuilder> packet_to_send_;
   std::list<std::unique_ptr<AclPacketBuilder>> fragments_to_send_;
   std::map<uint16_t, acl_connection>::iterator current_connection_pair_;
 
@@ -396,16 +1594,27 @@
   os::Handler* handler_ = nullptr;
   ConnectionCallbacks* client_callbacks_ = nullptr;
   os::Handler* client_handler_ = nullptr;
+  LeConnectionCallbacks* le_client_callbacks_ = nullptr;
+  os::Handler* le_client_handler_ = nullptr;
+  AclManagerCallbacks* acl_manager_client_callbacks_ = nullptr;
+  os::Handler* acl_manager_client_handler_ = nullptr;
   common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* hci_queue_end_ = nullptr;
   std::map<uint16_t, AclManager::acl_connection> acl_connections_;
-  std::set<common::Address> connecting_;
-  common::Callback<bool(common::Address, common::ClassOfDevice)> should_accept_connection_;
+  std::set<Address> connecting_;
+  std::set<AddressWithType> connecting_le_;
+  common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_;
+  std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_;
+  size_t hci_mtu_{0};
 };
 
 AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const {
   return manager_->pimpl_->get_acl_queue_end(handle_);
 }
 
+void AclConnection::RegisterCallbacks(ConnectionManagementCallbacks* callbacks, os::Handler* handler) {
+  return manager_->pimpl_->RegisterCallbacks(handle_, callbacks, handler);
+}
+
 void AclConnection::RegisterDisconnectCallback(common::OnceCallback<void(ErrorCode)> on_disconnect,
                                                os::Handler* handler) {
   return manager_->pimpl_->RegisterDisconnectCallback(handle_, std::move(on_disconnect), handler);
@@ -415,27 +1624,168 @@
   return manager_->pimpl_->Disconnect(handle_, reason);
 }
 
+bool AclConnection::ChangeConnectionPacketType(uint16_t packet_type) {
+  return manager_->pimpl_->ChangeConnectionPacketType(handle_, packet_type);
+}
+
+bool AclConnection::AuthenticationRequested() {
+  return manager_->pimpl_->AuthenticationRequested(handle_);
+}
+
+bool AclConnection::SetConnectionEncryption(Enable enable) {
+  return manager_->pimpl_->SetConnectionEncryption(handle_, enable);
+}
+
+bool AclConnection::ChangeConnectionLinkKey() {
+  return manager_->pimpl_->ChangeConnectionLinkKey(handle_);
+}
+
+bool AclConnection::ReadClockOffset() {
+  return manager_->pimpl_->ReadClockOffset(handle_);
+}
+
+bool AclConnection::HoldMode(uint16_t max_interval, uint16_t min_interval) {
+  return manager_->pimpl_->HoldMode(handle_, max_interval, min_interval);
+}
+
+bool AclConnection::SniffMode(uint16_t max_interval, uint16_t min_interval, uint16_t attempt, uint16_t timeout) {
+  return manager_->pimpl_->SniffMode(handle_, max_interval, min_interval, attempt, timeout);
+}
+
+bool AclConnection::ExitSniffMode() {
+  return manager_->pimpl_->ExitSniffMode(handle_);
+}
+
+bool AclConnection::QosSetup(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+                             uint32_t delay_variation) {
+  return manager_->pimpl_->QosSetup(handle_, service_type, token_rate, peak_bandwidth, latency, delay_variation);
+}
+
+bool AclConnection::RoleDiscovery() {
+  return manager_->pimpl_->RoleDiscovery(handle_);
+}
+
+bool AclConnection::ReadLinkPolicySettings() {
+  return manager_->pimpl_->ReadLinkPolicySettings(handle_);
+}
+
+bool AclConnection::WriteLinkPolicySettings(uint16_t link_policy_settings) {
+  return manager_->pimpl_->WriteLinkPolicySettings(handle_, link_policy_settings);
+}
+
+bool AclConnection::FlowSpecification(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                                      uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency) {
+  return manager_->pimpl_->FlowSpecification(handle_, flow_direction, service_type, token_rate, token_bucket_size,
+                                             peak_bandwidth, access_latency);
+}
+
+bool AclConnection::SniffSubrating(uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+                                   uint16_t minimum_local_timeout) {
+  return manager_->pimpl_->SniffSubrating(handle_, maximum_latency, minimum_remote_timeout, minimum_local_timeout);
+}
+
+bool AclConnection::Flush() {
+  return manager_->pimpl_->Flush(handle_);
+}
+
+bool AclConnection::ReadAutomaticFlushTimeout() {
+  return manager_->pimpl_->ReadAutomaticFlushTimeout(handle_);
+}
+
+bool AclConnection::WriteAutomaticFlushTimeout(uint16_t flush_timeout) {
+  return manager_->pimpl_->WriteAutomaticFlushTimeout(handle_, flush_timeout);
+}
+
+bool AclConnection::ReadTransmitPowerLevel(TransmitPowerLevelType type) {
+  return manager_->pimpl_->ReadTransmitPowerLevel(handle_, type);
+}
+
+bool AclConnection::ReadLinkSupervisionTimeout() {
+  return manager_->pimpl_->ReadLinkSupervisionTimeout(handle_);
+}
+
+bool AclConnection::WriteLinkSupervisionTimeout(uint16_t link_supervision_timeout) {
+  return manager_->pimpl_->WriteLinkSupervisionTimeout(handle_, link_supervision_timeout);
+}
+
+bool AclConnection::ReadFailedContactCounter() {
+  return manager_->pimpl_->ReadFailedContactCounter(handle_);
+}
+
+bool AclConnection::ResetFailedContactCounter() {
+  return manager_->pimpl_->ResetFailedContactCounter(handle_);
+}
+
+bool AclConnection::ReadLinkQuality() {
+  return manager_->pimpl_->ReadLinkQuality(handle_);
+}
+
+bool AclConnection::ReadAfhChannelMap() {
+  return manager_->pimpl_->ReadAfhChannelMap(handle_);
+}
+
+bool AclConnection::ReadRssi() {
+  return manager_->pimpl_->ReadRssi(handle_);
+}
+
+bool AclConnection::ReadClock(WhichClock which_clock) {
+  return manager_->pimpl_->ReadClock(handle_, which_clock);
+}
+
 void AclConnection::Finish() {
   return manager_->pimpl_->Finish(handle_);
 }
 
 AclManager::AclManager() : pimpl_(std::make_unique<impl>(*this)) {}
 
-bool AclManager::RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler) {
+void AclManager::RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler) {
   ASSERT(callbacks != nullptr && handler != nullptr);
   GetHandler()->Post(common::BindOnce(&impl::handle_register_callbacks, common::Unretained(pimpl_.get()),
                                       common::Unretained(callbacks), common::Unretained(handler)));
-  return true;
 }
 
-void AclManager::CreateConnection(common::Address address) {
+void AclManager::RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
+  ASSERT(callbacks != nullptr && handler != nullptr);
+  GetHandler()->Post(common::BindOnce(&impl::handle_register_le_callbacks, common::Unretained(pimpl_.get()),
+                                      common::Unretained(callbacks), common::Unretained(handler)));
+}
+
+void AclManager::RegisterAclManagerCallbacks(AclManagerCallbacks* callbacks, os::Handler* handler) {
+  ASSERT(callbacks != nullptr && handler != nullptr);
+  GetHandler()->Post(common::BindOnce(&impl::handle_register_acl_manager_callbacks, common::Unretained(pimpl_.get()),
+                                      common::Unretained(callbacks), common::Unretained(handler)));
+}
+
+void AclManager::CreateConnection(Address address) {
   GetHandler()->Post(common::BindOnce(&impl::create_connection, common::Unretained(pimpl_.get()), address));
 }
 
-void AclManager::CancelConnect(common::Address address) {
+void AclManager::CreateLeConnection(AddressWithType address_with_type) {
+  GetHandler()->Post(
+      common::BindOnce(&impl::create_le_connection, common::Unretained(pimpl_.get()), address_with_type));
+}
+
+void AclManager::CancelConnect(Address address) {
   GetHandler()->Post(BindOnce(&impl::cancel_connect, common::Unretained(pimpl_.get()), address));
 }
 
+void AclManager::MasterLinkKey(KeyFlag key_flag) {
+  GetHandler()->Post(BindOnce(&impl::master_link_key, common::Unretained(pimpl_.get()), key_flag));
+}
+
+void AclManager::SwitchRole(Address address, Role role) {
+  GetHandler()->Post(BindOnce(&impl::switch_role, common::Unretained(pimpl_.get()), address, role));
+}
+
+void AclManager::ReadDefaultLinkPolicySettings() {
+  GetHandler()->Post(BindOnce(&impl::read_default_link_policy_settings, common::Unretained(pimpl_.get())));
+}
+
+void AclManager::WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings) {
+  GetHandler()->Post(BindOnce(&impl::write_default_link_policy_settings, common::Unretained(pimpl_.get()),
+                              default_link_policy_settings));
+}
+
 void AclManager::ListDependencies(ModuleList* list) {
   list->add<HciLayer>();
   list->add<Controller>();
@@ -449,7 +1799,13 @@
   pimpl_->Stop();
 }
 
+std::string AclManager::ToString() const {
+  return "Acl Manager";
+}
+
 const ModuleFactory AclManager::Factory = ModuleFactory([]() { return new AclManager(); });
 
+AclManager::~AclManager() = default;
+
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/hci/acl_manager.h b/gd/hci/acl_manager.h
index d65b463..27c4fb3 100644
--- a/gd/hci/acl_manager.h
+++ b/gd/hci/acl_manager.h
@@ -18,9 +18,10 @@
 
 #include <memory>
 
-#include "common/address.h"
 #include "common/bidi_queue.h"
 #include "common/callback.h"
+#include "hci/address.h"
+#include "hci/address_with_type.h"
 #include "hci/hci_layer.h"
 #include "hci/hci_packets.h"
 #include "module.h"
@@ -31,57 +32,200 @@
 
 class AclManager;
 
+class ConnectionManagementCallbacks {
+ public:
+  virtual ~ConnectionManagementCallbacks() = default;
+  // Invoked when controller sends Connection Packet Type Changed event with Success error code
+  virtual void OnConnectionPacketTypeChanged(uint16_t packet_type) = 0;
+  // Invoked when controller sends Authentication Complete event with Success error code
+  virtual void OnAuthenticationComplete() = 0;
+  // Invoked when controller sends Encryption Change event with Success error code
+  virtual void OnEncryptionChange(EncryptionEnabled enabled) = 0;
+  // Invoked when controller sends Change Connection Link Key Complete event with Success error code
+  virtual void OnChangeConnectionLinkKeyComplete() = 0;
+  // Invoked when controller sends Read Clock Offset Complete event with Success error code
+  virtual void OnReadClockOffsetComplete(uint16_t clock_offset) = 0;
+  // Invoked when controller sends Mode Change event with Success error code
+  virtual void OnModeChange(Mode current_mode, uint16_t interval) = 0;
+  // Invoked when controller sends QoS Setup Complete event with Success error code
+  virtual void OnQosSetupComplete(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+                                  uint32_t latency, uint32_t delay_variation) = 0;
+  // Invoked when controller sends Flow Specification Complete event with Success error code
+  virtual void OnFlowSpecificationComplete(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                                           uint32_t token_bucket_size, uint32_t peak_bandwidth,
+                                           uint32_t access_latency) = 0;
+  // Invoked when controller sends Flush Occurred event
+  virtual void OnFlushOccurred() = 0;
+  // Invoked when controller sends Command Complete event for Role Discovery command with Success error code
+  virtual void OnRoleDiscoveryComplete(Role current_role) = 0;
+  // Invoked when controller sends Command Complete event for Read Link Policy Settings command with Success error code
+  virtual void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) = 0;
+  // Invoked when controller sends Command Complete event for Read Automatic Flush Timeout command with Success error
+  // code
+  virtual void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) = 0;
+  // Invoked when controller sends Command Complete event for Read Transmit Power Level command with Success error code
+  virtual void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) = 0;
+  // Invoked when controller sends Command Complete event for Read Link Supervision Time out command with Success error
+  // code
+  virtual void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) = 0;
+  // Invoked when controller sends Command Complete event for Read Failed Contact Counter command with Success error
+  // code
+  virtual void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) = 0;
+  // Invoked when controller sends Command Complete event for Read Link Quality command with Success error code
+  virtual void OnReadLinkQualityComplete(uint8_t link_quality) = 0;
+  // Invoked when controller sends Command Complete event for Read AFH Channel Map command with Success error code
+  virtual void OnReadAfhChannelMapComplete(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) = 0;
+  // Invoked when controller sends Command Complete event for Read RSSI command with Success error code
+  virtual void OnReadRssiComplete(uint8_t rssi) = 0;
+  // Invoked when controller sends Command Complete event for Read Clock command with Success error code
+  virtual void OnReadClockComplete(uint32_t clock, uint16_t accuracy) = 0;
+};
+
 class AclConnection {
  public:
-  AclConnection() : manager_(nullptr) {}
+  AclConnection()
+      : manager_(nullptr), handle_(0), address_(Address::kEmpty), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS){};
+  virtual ~AclConnection() = default;
 
-  common::Address GetAddress() const {
+  virtual Address GetAddress() const {
     return address_;
   }
 
+  virtual AddressType GetAddressType() const {
+    return address_type_;
+  }
+
+  uint16_t GetHandle() const {
+    return handle_;
+  }
+
+  /* This return role for LE devices only, for Classic, please see |RoleDiscovery| method.
+   * TODO: split AclConnection for LE and Classic
+   */
+  Role GetRole() const {
+    return role_;
+  }
+
   using Queue = common::BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder>;
   using QueueUpEnd = common::BidiQueueEnd<BasePacketBuilder, PacketView<kLittleEndian>>;
   using QueueDownEnd = common::BidiQueueEnd<PacketView<kLittleEndian>, BasePacketBuilder>;
-  QueueUpEnd* GetAclQueueEnd() const;
-  void RegisterDisconnectCallback(common::OnceCallback<void(ErrorCode)> on_disconnect, os::Handler* handler);
-  bool Disconnect(DisconnectReason);
+  virtual QueueUpEnd* GetAclQueueEnd() const;
+  virtual void RegisterCallbacks(ConnectionManagementCallbacks* callbacks, os::Handler* handler);
+  virtual void RegisterDisconnectCallback(common::OnceCallback<void(ErrorCode)> on_disconnect, os::Handler* handler);
+  virtual bool Disconnect(DisconnectReason reason);
+  virtual bool ChangeConnectionPacketType(uint16_t packet_type);
+  virtual bool AuthenticationRequested();
+  virtual bool SetConnectionEncryption(Enable enable);
+  virtual bool ChangeConnectionLinkKey();
+  virtual bool ReadClockOffset();
+  virtual bool HoldMode(uint16_t max_interval, uint16_t min_interval);
+  virtual bool SniffMode(uint16_t max_interval, uint16_t min_interval, uint16_t attempt, uint16_t timeout);
+  virtual bool ExitSniffMode();
+  virtual bool QosSetup(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+                        uint32_t delay_variation);
+  virtual bool RoleDiscovery();
+  virtual bool ReadLinkPolicySettings();
+  virtual bool WriteLinkPolicySettings(uint16_t link_policy_settings);
+  virtual bool FlowSpecification(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                                 uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency);
+  virtual bool SniffSubrating(uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+                              uint16_t minimum_local_timeout);
+  virtual bool Flush();
+  virtual bool ReadAutomaticFlushTimeout();
+  virtual bool WriteAutomaticFlushTimeout(uint16_t flush_timeout);
+  virtual bool ReadTransmitPowerLevel(TransmitPowerLevelType type);
+  virtual bool ReadLinkSupervisionTimeout();
+  virtual bool WriteLinkSupervisionTimeout(uint16_t link_supervision_timeout);
+  virtual bool ReadFailedContactCounter();
+  virtual bool ResetFailedContactCounter();
+  virtual bool ReadLinkQuality();
+  virtual bool ReadAfhChannelMap();
+  virtual bool ReadRssi();
+  virtual bool ReadClock(WhichClock which_clock);
+
   // Ask AclManager to clean me up. Must invoke after on_disconnect is called
-  void Finish();
+  virtual void Finish();
 
   // TODO: API to change link settings ... ?
 
  private:
   friend AclManager;
-  AclConnection(AclManager* manager, uint16_t handle, common::Address address)
+  AclConnection(const AclManager* manager, uint16_t handle, Address address)
       : manager_(manager), handle_(handle), address_(address) {}
-  AclManager* manager_;
+  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) {}
+  const AclManager* manager_;
   uint16_t handle_;
-  common::Address address_;
+  Address address_;
+  AddressType address_type_;
+  Role role_;
+  DISALLOW_COPY_AND_ASSIGN(AclConnection);
 };
 
 class ConnectionCallbacks {
  public:
   virtual ~ConnectionCallbacks() = default;
   // Invoked when controller sends Connection Complete event with Success error code
-  virtual void OnConnectSuccess(AclConnection /* , initiated_by_local ? */) = 0;
+  virtual void OnConnectSuccess(std::unique_ptr<AclConnection> /* , initiated_by_local ? */) = 0;
   // Invoked when controller sends Connection Complete event with non-Success error code
-  virtual void OnConnectFail(common::Address, ErrorCode reason) = 0;
+  virtual void OnConnectFail(Address, ErrorCode reason) = 0;
+};
+
+class LeConnectionCallbacks {
+ public:
+  virtual ~LeConnectionCallbacks() = default;
+  // Invoked when controller sends Connection Complete event with Success error code
+  // AddressWithType is always equal to the object used in AclManager#CreateLeConnection
+  virtual void OnLeConnectSuccess(AddressWithType, std::unique_ptr<AclConnection> /* , initiated_by_local ? */) = 0;
+  // Invoked when controller sends Connection Complete event with non-Success error code
+  virtual void OnLeConnectFail(AddressWithType, ErrorCode reason) = 0;
+};
+
+class AclManagerCallbacks {
+ public:
+  virtual ~AclManagerCallbacks() = default;
+  // Invoked when controller sends Master Link Key Complete event with Success error code
+  virtual void OnMasterLinkKeyComplete(uint16_t connection_handle, KeyFlag key_flag) = 0;
+  // Invoked when controller sends Role Change event with Success error code
+  virtual void OnRoleChange(Address bd_addr, Role new_role) = 0;
+  // Invoked when controller sends Command Complete event for Read Default Link Policy Settings command with Success
+  // error code
+  virtual void OnReadDefaultLinkPolicySettingsComplete(uint16_t default_link_policy_settings) = 0;
 };
 
 class AclManager : public Module {
  public:
   AclManager();
+  // NOTE: It is necessary to forward declare a default destructor that overrides the base class one, because
+  // "struct impl" is forwarded declared in .cc and compiler needs a concrete definition of "struct impl" when
+  // compiling AclManager's destructor. Hence we need to forward declare the destructor for AclManager to delay
+  // compiling AclManager's destructor until it starts linking the .cc file.
+  ~AclManager() override;
 
-  // Returns true if callbacks are successfully registered. Should register only once when user module starts.
+  // Should register only once when user module starts.
   // Generates OnConnectSuccess when an incoming connection is established.
-  bool RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler);
+  virtual void RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler);
+
+  // Should register only once when user module starts.
+  virtual void RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler);
+
+  // Should register only once when user module starts.
+  virtual void RegisterAclManagerCallbacks(AclManagerCallbacks* callbacks, os::Handler* handler);
 
   // Generates OnConnectSuccess if connected, or OnConnectFail otherwise
-  void CreateConnection(common::Address address);
+  virtual void CreateConnection(Address address);
+
+  // Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise
+  virtual void CreateLeConnection(AddressWithType address_with_type);
 
   // Generates OnConnectFail with error code "terminated by local host 0x16" if cancelled, or OnConnectSuccess if not
   // successfully cancelled and already connected
-  void CancelConnect(common::Address address);
+  virtual void CancelConnect(Address address);
+
+  virtual void MasterLinkKey(KeyFlag key_flag);
+  virtual void SwitchRole(Address address, Role role);
+  virtual void ReadDefaultLinkPolicySettings();
+  virtual void WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings);
 
   static const ModuleFactory Factory;
 
@@ -92,6 +236,8 @@
 
   void Stop() override;
 
+  std::string ToString() const override;
+
  private:
   friend AclConnection;
 
@@ -99,6 +245,7 @@
   std::unique_ptr<impl> pimpl_;
 
   struct acl_connection;
+  DISALLOW_COPY_AND_ASSIGN(AclManager);
 };
 
 }  // namespace hci
diff --git a/gd/hci/acl_manager_mock.h b/gd/hci/acl_manager_mock.h
new file mode 100644
index 0000000..e7a8c6b
--- /dev/null
+++ b/gd/hci/acl_manager_mock.h
@@ -0,0 +1,52 @@
+/*
+ * 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 "hci/acl_manager.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace hci {
+namespace testing {
+
+class MockAclConnection : public AclConnection {
+ public:
+  MOCK_METHOD(Address, GetAddress, (), (const, override));
+  MOCK_METHOD(AddressType, GetAddressType, (), (const, override));
+  MOCK_METHOD(void, RegisterDisconnectCallback,
+              (common::OnceCallback<void(ErrorCode)> on_disconnect, os::Handler* handler), (override));
+  MOCK_METHOD(bool, Disconnect, (DisconnectReason reason), (override));
+  MOCK_METHOD(void, Finish, (), (override));
+  QueueUpEnd* GetAclQueueEnd() const override {
+    return acl_queue_.GetUpEnd();
+  }
+  mutable common::BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> acl_queue_{10};
+};
+
+class MockAclManager : public AclManager {
+ public:
+  MOCK_METHOD(void, RegisterCallbacks, (ConnectionCallbacks * callbacks, os::Handler* handler), (override));
+  MOCK_METHOD(void, RegisterLeCallbacks, (LeConnectionCallbacks * callbacks, os::Handler* handler), (override));
+  MOCK_METHOD(void, CreateConnection, (Address address), (override));
+  MOCK_METHOD(void, CreateLeConnection, (AddressWithType address_with_type), (override));
+  MOCK_METHOD(void, CancelConnect, (Address address), (override));
+};
+
+}  // namespace testing
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/acl_manager_test.cc b/gd/hci/acl_manager_test.cc
index 65388f7..8b2cb32 100644
--- a/gd/hci/acl_manager_test.cc
+++ b/gd/hci/acl_manager_test.cc
@@ -24,8 +24,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
-#include "common/address.h"
 #include "common/bind.h"
+#include "hci/address.h"
 #include "hci/controller.h"
 #include "hci/hci_layer.h"
 #include "os/thread.h"
@@ -35,7 +35,6 @@
 namespace hci {
 namespace {
 
-using common::Address;
 using common::BidiQueue;
 using common::BidiQueueEnd;
 using packet::kLittleEndian;
@@ -74,11 +73,11 @@
     acl_cb_handler_ = handler;
   }
 
-  uint16_t GetControllerAclPacketLength() override {
+  uint16_t GetControllerAclPacketLength() const override {
     return acl_buffer_length_;
   }
 
-  uint16_t GetControllerNumAclPacketBuffers() override {
+  uint16_t GetControllerNumAclPacketBuffers() const override {
     return total_acl_buffers_;
   }
 
@@ -102,11 +101,14 @@
   void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
                       common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
     command_queue_.push(std::move(command));
+    not_empty_.notify_all();
   }
 
   void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
                       common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
     command_queue_.push(std::move(command));
+    command_complete_callbacks.push_front(std::move(on_complete));
+    not_empty_.notify_all();
   }
 
   std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
@@ -118,6 +120,20 @@
     return last;
   }
 
+  ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    std::chrono::milliseconds time = std::chrono::milliseconds(3000);
+
+    ASSERT(not_empty_.wait_for(lock, time) != std::cv_status::timeout);
+    auto packet_view = GetPacketView(GetLastCommand());
+    CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+    ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+    ASSERT(command.IsValid());
+    EXPECT_EQ(command.GetOpCode(), op_code);
+
+    return command;
+  }
+
   void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
                             os::Handler* handler) override {
     registered_events_[event_code] = event_handler;
@@ -127,6 +143,15 @@
     registered_events_.erase(event_code);
   }
 
+  void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+                              os::Handler* handler) override {
+    registered_le_events_[subevent_code] = event_handler;
+  }
+
+  void UnregisterLeEventHandler(SubeventCode subevent_code) {
+    registered_le_events_.erase(subevent_code);
+  }
+
   void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
     auto packet = GetPacketView(std::move(event_builder));
     EventPacketView event = EventPacketView::Create(packet);
@@ -136,6 +161,16 @@
     registered_events_[event_code].Run(event);
   }
 
+  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+    EXPECT_TRUE(meta_event_view.IsValid());
+    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+    EXPECT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
+    registered_le_events_[subevent_code].Run(meta_event_view);
+  }
+
   void IncomingAclData(uint16_t handle) {
     os::Handler* hci_handler = GetHandler();
     auto* queue_end = acl_queue_.GetDownEnd();
@@ -160,6 +195,13 @@
     EXPECT_EQ(queue_end->TryDequeue(), nullptr);
   }
 
+  void CommandCompleteCallback(EventPacketView event) {
+    CommandCompleteView complete_view = CommandCompleteView::Create(event);
+    ASSERT(complete_view.IsValid());
+    std::move(command_complete_callbacks.front()).Run(complete_view);
+    command_complete_callbacks.pop_front();
+  }
+
   PacketView<kLittleEndian> OutgoingAclData() {
     auto queue_end = acl_queue_.GetDownEnd();
     std::unique_ptr<AclPacketBuilder> received;
@@ -180,9 +222,13 @@
 
  private:
   std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+  std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+  std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
   BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
 
   std::queue<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+  mutable std::mutex mutex_;
+  std::condition_variable not_empty_;
 };
 
 class AclManagerNoCallbacksTest : public ::testing::Test {
@@ -218,12 +264,23 @@
     return mock_connection_callback_.connection_promise_->get_future();
   }
 
-  AclConnection& GetLastConnection() {
+  std::future<void> GetLeConnectionFuture() {
+    ASSERT_LOG(mock_le_connection_callbacks_.le_connection_promise_ == nullptr,
+               "Promises promises ... Only one at a time");
+    mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
+    return mock_le_connection_callbacks_.le_connection_promise_->get_future();
+  }
+
+  std::shared_ptr<AclConnection> GetLastConnection() {
     return mock_connection_callback_.connections_.back();
   }
 
-  void SendAclData(uint16_t handle, AclConnection connection) {
-    auto queue_end = connection.GetAclQueueEnd();
+  std::shared_ptr<AclConnection> GetLastLeConnection() {
+    return mock_le_connection_callbacks_.le_connections_.back();
+  }
+
+  void SendAclData(uint16_t handle, std::shared_ptr<AclConnection> connection) {
+    auto queue_end = connection->GetAclQueueEnd();
     std::promise<void> promise;
     auto future = promise.get_future();
     queue_end->RegisterEnqueue(client_handler_,
@@ -240,18 +297,41 @@
 
   class MockConnectionCallback : public ConnectionCallbacks {
    public:
-    void OnConnectSuccess(AclConnection connection) override {
-      connections_.push_back(connection);
+    void OnConnectSuccess(std::unique_ptr<AclConnection> connection) override {
+      // Convert to std::shared_ptr during push_back()
+      connections_.push_back(std::move(connection));
       if (connection_promise_ != nullptr) {
         connection_promise_->set_value();
         connection_promise_.reset();
       }
     }
-    MOCK_METHOD2(OnConnectFail, void(Address, ErrorCode reason));
+    MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
 
-    std::list<AclConnection> connections_;
+    std::list<std::shared_ptr<AclConnection>> connections_;
     std::unique_ptr<std::promise<void>> connection_promise_;
   } mock_connection_callback_;
+
+  class MockLeConnectionCallbacks : public LeConnectionCallbacks {
+   public:
+    void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<AclConnection> connection) override {
+      le_connections_.push_back(std::move(connection));
+      if (le_connection_promise_ != nullptr) {
+        le_connection_promise_->set_value();
+        le_connection_promise_.reset();
+      }
+    }
+    MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
+
+    std::list<std::shared_ptr<AclConnection>> le_connections_;
+    std::unique_ptr<std::promise<void>> le_connection_promise_;
+  } mock_le_connection_callbacks_;
+
+  class MockAclManagerCallbacks : public AclManagerCallbacks {
+   public:
+    MOCK_METHOD(void, OnMasterLinkKeyComplete, (uint16_t connection_handle, KeyFlag key_flag), (override));
+    MOCK_METHOD(void, OnRoleChange, (Address bd_addr, Role new_role), (override));
+    MOCK_METHOD(void, OnReadDefaultLinkPolicySettingsComplete, (uint16_t default_link_policy_settings), (override));
+  } mock_acl_manager_callbacks_;
 };
 
 class AclManagerTest : public AclManagerNoCallbacksTest {
@@ -259,13 +339,73 @@
   void SetUp() override {
     AclManagerNoCallbacksTest::SetUp();
     acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
+    acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
+    acl_manager_->RegisterAclManagerCallbacks(&mock_acl_manager_callbacks_, client_handler_);
   }
 };
 
+class AclManagerWithConnectionTest : public AclManagerTest {
+ protected:
+  void SetUp() override {
+    AclManagerTest::SetUp();
+    test_hci_layer_->RegisterEventHandler(
+        EventCode::COMMAND_COMPLETE,
+        base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(test_hci_layer_)), nullptr);
+
+    handle_ = 0x123;
+    acl_manager_->CreateConnection(remote);
+
+    // Wait for the connection request
+    std::unique_ptr<CommandPacketBuilder> last_command;
+    do {
+      last_command = test_hci_layer_->GetLastCommand();
+    } while (last_command == nullptr);
+
+    auto first_connection = GetConnectionFuture();
+    test_hci_layer_->IncomingEvent(
+        ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
+
+    auto first_connection_status = first_connection.wait_for(kTimeout);
+    ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+    connection_ = GetLastConnection();
+    connection_->RegisterCallbacks(&mock_connection_management_callbacks_, client_handler_);
+  }
+
+  uint16_t handle_;
+  std::shared_ptr<AclConnection> connection_;
+
+  class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks {
+   public:
+    MOCK_METHOD1(OnConnectionPacketTypeChanged, void(uint16_t packet_type));
+    MOCK_METHOD0(OnAuthenticationComplete, void());
+    MOCK_METHOD1(OnEncryptionChange, void(EncryptionEnabled enabled));
+    MOCK_METHOD0(OnChangeConnectionLinkKeyComplete, void());
+    MOCK_METHOD1(OnReadClockOffsetComplete, void(uint16_t clock_offse));
+    MOCK_METHOD2(OnModeChange, void(Mode current_mode, uint16_t interval));
+    MOCK_METHOD5(OnQosSetupComplete, void(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+                                          uint32_t latency, uint32_t delay_variation));
+    MOCK_METHOD6(OnFlowSpecificationComplete,
+                 void(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                      uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency));
+    MOCK_METHOD0(OnFlushOccurred, void());
+    MOCK_METHOD1(OnRoleDiscoveryComplete, void(Role current_role));
+    MOCK_METHOD1(OnReadLinkPolicySettingsComplete, void(uint16_t link_policy_settings));
+    MOCK_METHOD1(OnReadAutomaticFlushTimeoutComplete, void(uint16_t flush_timeout));
+    MOCK_METHOD1(OnReadTransmitPowerLevelComplete, void(uint8_t transmit_power_level));
+    MOCK_METHOD1(OnReadLinkSupervisionTimeoutComplete, void(uint16_t link_supervision_timeout));
+    MOCK_METHOD1(OnReadFailedContactCounterComplete, void(uint16_t failed_contact_counter));
+    MOCK_METHOD1(OnReadLinkQualityComplete, void(uint8_t link_quality));
+    MOCK_METHOD2(OnReadAfhChannelMapComplete, void(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map));
+    MOCK_METHOD1(OnReadRssiComplete, void(uint8_t rssi));
+    MOCK_METHOD2(OnReadClockComplete, void(uint32_t clock, uint16_t accuracy));
+  } mock_connection_management_callbacks_;
+};
+
 TEST_F(AclManagerTest, startup_teardown) {}
 
 TEST_F(AclManagerNoCallbacksTest, acl_connection_before_registered_callbacks) {
-  common::ClassOfDevice class_of_device;
+  ClassOfDevice class_of_device;
 
   test_hci_layer_->IncomingEvent(
       ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
@@ -299,8 +439,8 @@
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
 
-  AclConnection& connection = GetLastConnection();
-  ASSERT_EQ(connection.GetAddress(), remote);
+  std::shared_ptr<AclConnection> connection = GetLastConnection();
+  ASSERT_EQ(connection->GetAddress(), remote);
 }
 
 TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) {
@@ -322,6 +462,48 @@
   fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
 }
 
+TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_success) {
+  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+  acl_manager_->CreateLeConnection(remote_with_type);
+
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
+  auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
+  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetPeerAddress(), remote);
+  EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
+
+  auto first_connection = GetLeConnectionFuture();
+
+  test_hci_layer_->IncomingLeMetaEvent(
+      LeConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS,
+                                          remote, 0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
+
+  auto first_connection_status = first_connection.wait_for(kTimeout);
+  ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+  std::shared_ptr<AclConnection> connection = GetLastLeConnection();
+  ASSERT_EQ(connection->GetAddress(), remote);
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
+  AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+  acl_manager_->CreateLeConnection(remote_with_type);
+
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
+  auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
+  auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetPeerAddress(), remote);
+  EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
+
+  EXPECT_CALL(mock_le_connection_callbacks_,
+              OnLeConnectFail(remote_with_type, ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES));
+  test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
+      ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS, remote,
+      0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
+}
+
 TEST_F(AclManagerTest, invoke_registered_callback_disconnection_complete) {
   uint16_t handle = 0x123;
 
@@ -341,12 +523,12 @@
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
 
-  AclConnection& connection = GetLastConnection();
+  std::shared_ptr<AclConnection> connection = GetLastConnection();
 
   // Register the disconnect handler
   std::promise<ErrorCode> promise;
   auto future = promise.get_future();
-  connection.RegisterDisconnectCallback(
+  connection->RegisterDisconnectCallback(
       common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode reason) { promise.set_value(reason); },
                        std::move(promise)),
       client_handler_);
@@ -380,12 +562,12 @@
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
 
-  AclConnection& connection = GetLastConnection();
+  std::shared_ptr<AclConnection> connection = GetLastConnection();
 
   // Register the disconnect handler
   std::promise<ErrorCode> promise;
   auto future = promise.get_future();
-  connection.RegisterDisconnectCallback(
+  connection->RegisterDisconnectCallback(
       common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode reason) { promise.set_value(reason); },
                        std::move(promise)),
       client_handler_);
@@ -397,7 +579,7 @@
   ASSERT_EQ(disconnection_status, std::future_status::ready);
   ASSERT_EQ(ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF, future.get());
 
-  connection.Finish();
+  connection->Finish();
 }
 
 TEST_F(AclManagerTest, acl_send_data_one_connection) {
@@ -419,15 +601,16 @@
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
 
-  AclConnection& connection = GetLastConnection();
+  std::shared_ptr<AclConnection> connection = GetLastConnection();
 
   // Register the disconnect handler
-  connection.RegisterDisconnectCallback(common::Bind([](AclConnection conn, ErrorCode) { conn.Finish(); }, connection),
-                                        client_handler_);
+  connection->RegisterDisconnectCallback(
+      common::Bind([](std::shared_ptr<AclConnection> conn, ErrorCode) { conn->Finish(); }, connection),
+      client_handler_);
 
   // Send a packet from HCI
   test_hci_layer_->IncomingAclData(handle);
-  auto queue_end = connection.GetAclQueueEnd();
+  auto queue_end = connection->GetAclQueueEnd();
 
   std::unique_ptr<PacketView<kLittleEndian>> received;
   do {
@@ -445,7 +628,7 @@
   SendAclData(handle, connection);
 
   sent_packet = test_hci_layer_->OutgoingAclData();
-  connection.Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
+  connection->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
 }
 
 TEST_F(AclManagerTest, acl_send_data_credits) {
@@ -466,11 +649,12 @@
   auto first_connection_status = first_connection.wait_for(kTimeout);
   ASSERT_EQ(first_connection_status, std::future_status::ready);
 
-  AclConnection& connection = GetLastConnection();
+  std::shared_ptr<AclConnection> connection = GetLastConnection();
 
   // Register the disconnect handler
-  connection.RegisterDisconnectCallback(
-      common::BindOnce([](AclConnection conn, ErrorCode) { conn.Finish(); }, std::move(connection)), client_handler_);
+  connection->RegisterDisconnectCallback(
+      common::BindOnce([](std::shared_ptr<AclConnection> conn, ErrorCode) { conn->Finish(); }, connection),
+      client_handler_);
 
   // Use all the credits
   for (uint16_t credits = 0; credits < test_controller_->total_acl_buffers_; credits++) {
@@ -489,7 +673,341 @@
 
   auto after_credits_sent_packet = test_hci_layer_->OutgoingAclData();
 
-  connection.Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
+  connection->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
+}
+
+TEST_F(AclManagerWithConnectionTest, send_switch_role) {
+  acl_manager_->SwitchRole(connection_->GetAddress(), Role::SLAVE);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::SWITCH_ROLE);
+  auto command_view = SwitchRoleView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetBdAddr(), connection_->GetAddress());
+  EXPECT_EQ(command_view.GetRole(), Role::SLAVE);
+
+  EXPECT_CALL(mock_acl_manager_callbacks_, OnRoleChange(connection_->GetAddress(), Role::SLAVE));
+  test_hci_layer_->IncomingEvent(RoleChangeBuilder::Create(ErrorCode::SUCCESS, connection_->GetAddress(), Role::SLAVE));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_default_link_policy_settings) {
+  acl_manager_->ReadDefaultLinkPolicySettings();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS);
+  auto command_view = ReadDefaultLinkPolicySettingsView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_acl_manager_callbacks_, OnReadDefaultLinkPolicySettingsComplete(0x07));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_default_link_policy_settings) {
+  acl_manager_->WriteDefaultLinkPolicySettings(0x05);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+  auto command_view = WriteDefaultLinkPolicySettingsView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetDefaultLinkPolicySettings(), 0x05);
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      WriteDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_change_connection_packet_type) {
+  connection_->ChangeConnectionPacketType(0xEE1C);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::CHANGE_CONNECTION_PACKET_TYPE);
+  auto command_view = ChangeConnectionPacketTypeView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetPacketType(), 0xEE1C);
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnConnectionPacketTypeChanged(0xEE1C));
+  test_hci_layer_->IncomingEvent(ConnectionPacketTypeChangedBuilder::Create(ErrorCode::SUCCESS, handle_, 0xEE1C));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_authentication_requested) {
+  connection_->AuthenticationRequested();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::AUTHENTICATION_REQUESTED);
+  auto command_view = AuthenticationRequestedView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnAuthenticationComplete);
+  test_hci_layer_->IncomingEvent(AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) {
+  connection_->ReadClockOffset();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_CLOCK_OFFSET);
+  auto command_view = ReadClockOffsetView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockOffsetComplete(0x0123));
+  test_hci_layer_->IncomingEvent(ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_hold_mode) {
+  connection_->HoldMode(0x0500, 0x0020);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::HOLD_MODE);
+  auto command_view = HoldModeView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetHoldModeMaxInterval(), 0x0500);
+  EXPECT_EQ(command_view.GetHoldModeMinInterval(), 0x0020);
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::HOLD, 0x0020));
+  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_sniff_mode) {
+  connection_->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::SNIFF_MODE);
+  auto command_view = SniffModeView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetSniffMaxInterval(), 0x0500);
+  EXPECT_EQ(command_view.GetSniffMinInterval(), 0x0020);
+  EXPECT_EQ(command_view.GetSniffAttempt(), 0x0040);
+  EXPECT_EQ(command_view.GetSniffTimeout(), 0x0014);
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::SNIFF, 0x0028));
+  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_exit_sniff_mode) {
+  connection_->ExitSniffMode();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::EXIT_SNIFF_MODE);
+  auto command_view = ExitSniffModeView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::ACTIVE, 0x00));
+  test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_qos_setup) {
+  connection_->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::QOS_SETUP);
+  auto command_view = QosSetupView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
+  EXPECT_EQ(command_view.GetTokenRate(), 0x1234);
+  EXPECT_EQ(command_view.GetPeakBandwidth(), 0x1233);
+  EXPECT_EQ(command_view.GetLatency(), 0x1232);
+  EXPECT_EQ(command_view.GetDelayVariation(), 0x1231);
+
+  EXPECT_CALL(mock_connection_management_callbacks_,
+              OnQosSetupComplete(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+  test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT,
+                                                                 0x1234, 0x1233, 0x1232, 0x1231));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_flow_specification) {
+  connection_->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232,
+                                 0x1231);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::FLOW_SPECIFICATION);
+  auto command_view = FlowSpecificationView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetFlowDirection(), FlowDirection::OUTGOING_FLOW);
+  EXPECT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
+  EXPECT_EQ(command_view.GetTokenRate(), 0x1234);
+  EXPECT_EQ(command_view.GetTokenBucketSize(), 0x1233);
+  EXPECT_EQ(command_view.GetPeakBandwidth(), 0x1232);
+  EXPECT_EQ(command_view.GetAccessLatency(), 0x1231);
+
+  EXPECT_CALL(mock_connection_management_callbacks_,
+              OnFlowSpecificationComplete(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
+                                          0x1232, 0x1231));
+  test_hci_layer_->IncomingEvent(
+      FlowSpecificationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, FlowDirection::OUTGOING_FLOW,
+                                               ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_flush) {
+  connection_->Flush();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::FLUSH);
+  auto command_view = FlushView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnFlushOccurred());
+  test_hci_layer_->IncomingEvent(FlushOccurredBuilder::Create(handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_role_discovery) {
+  connection_->RoleDiscovery();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::ROLE_DISCOVERY);
+  auto command_view = RoleDiscoveryView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnRoleDiscoveryComplete(Role::MASTER));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      RoleDiscoveryCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, Role::MASTER));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_policy_settings) {
+  connection_->ReadLinkPolicySettings();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_POLICY_SETTINGS);
+  auto command_view = ReadLinkPolicySettingsView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkPolicySettingsComplete(0x07));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_link_policy_settings) {
+  connection_->WriteLinkPolicySettings(0x05);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_LINK_POLICY_SETTINGS);
+  auto command_view = WriteLinkPolicySettingsView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetLinkPolicySettings(), 0x05);
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      WriteLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_sniff_subrating) {
+  connection_->SniffSubrating(0x1234, 0x1235, 0x1236);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::SNIFF_SUBRATING);
+  auto command_view = SniffSubratingView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetMaximumLatency(), 0x1234);
+  EXPECT_EQ(command_view.GetMinimumRemoteTimeout(), 0x1235);
+  EXPECT_EQ(command_view.GetMinimumLocalTimeout(), 0x1236);
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_automatic_flush_timeout) {
+  connection_->ReadAutomaticFlushTimeout();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
+  auto command_view = ReadAutomaticFlushTimeoutView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadAutomaticFlushTimeoutComplete(0x07ff));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_automatic_flush_timeout) {
+  connection_->WriteAutomaticFlushTimeout(0x07FF);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
+  auto command_view = WriteAutomaticFlushTimeoutView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetFlushTimeout(), 0x07FF);
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      WriteAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_transmit_power_level) {
+  connection_->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_TRANSMIT_POWER_LEVEL);
+  auto command_view = ReadTransmitPowerLevelView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetType(), TransmitPowerLevelType::CURRENT);
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadTransmitPowerLevelComplete(0x07));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadTransmitPowerLevelCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_supervision_timeout) {
+  connection_->ReadLinkSupervisionTimeout();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
+  auto command_view = ReadLinkSupervisionTimeoutView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkSupervisionTimeoutComplete(0x5677));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_link_supervision_timeout) {
+  connection_->WriteLinkSupervisionTimeout(0x5678);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
+  auto command_view = WriteLinkSupervisionTimeoutView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetLinkSupervisionTimeout(), 0x5678);
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      WriteLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_failed_contact_counter) {
+  connection_->ReadFailedContactCounter();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_FAILED_CONTACT_COUNTER);
+  auto command_view = ReadFailedContactCounterView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadFailedContactCounterComplete(0x00));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_reset_failed_contact_counter) {
+  connection_->ResetFailedContactCounter();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::RESET_FAILED_CONTACT_COUNTER);
+  auto command_view = ResetFailedContactCounterView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ResetFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_quality) {
+  connection_->ReadLinkQuality();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_QUALITY);
+  auto command_view = ReadLinkQualityView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkQualityComplete(0xa9));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadLinkQualityCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0xa9));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_afh_channel_map) {
+  connection_->ReadAfhChannelMap();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_AFH_CHANNEL_MAP);
+  auto command_view = ReadAfhChannelMapView::Create(packet);
+  ASSERT(command_view.IsValid());
+  std::array<uint8_t, 10> afh_channel_map = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
+
+  EXPECT_CALL(mock_connection_management_callbacks_,
+              OnReadAfhChannelMapComplete(AfhMode::AFH_ENABLED, afh_channel_map));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_,
+                                                                          AfhMode::AFH_ENABLED, afh_channel_map));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_rssi) {
+  connection_->ReadRssi();
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_RSSI);
+  auto command_view = ReadRssiView::Create(packet);
+  ASSERT(command_view.IsValid());
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadRssiComplete(0x00));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_clock) {
+  connection_->ReadClock(WhichClock::LOCAL);
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_CLOCK);
+  auto command_view = ReadClockView::Create(packet);
+  ASSERT(command_view.IsValid());
+  EXPECT_EQ(command_view.GetWhichClock(), WhichClock::LOCAL);
+
+  EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockComplete(0x00002e6a, 0x0000));
+  uint8_t num_packets = 1;
+  test_hci_layer_->IncomingEvent(
+      ReadClockCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
 }
 
 }  // namespace
diff --git a/gd/common/address.cc b/gd/hci/address.cc
similarity index 90%
rename from gd/common/address.cc
rename to gd/hci/address.cc
index cd8101a..db0695d 100644
--- a/gd/common/address.cc
+++ b/gd/hci/address.cc
@@ -16,7 +16,7 @@
  *
  ******************************************************************************/
 
-#include "address.h"
+#include "hci/address.h"
 
 #include <stdint.h>
 #include <algorithm>
@@ -24,7 +24,7 @@
 #include <vector>
 
 namespace bluetooth {
-namespace common {
+namespace hci {
 
 static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
 
@@ -37,8 +37,8 @@
 
 std::string Address::ToString() const {
   char buffer[] = "00:00:00:00:00:00";
-  std::snprintf(&buffer[0], sizeof(buffer),
-      "%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1], address[0]);
+  std::snprintf(&buffer[0], sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3],
+                address[2], address[1], address[0]);
   std::string str(buffer);
   return str;
 }
@@ -88,5 +88,5 @@
   return Address::FromString(address, tmp);
 }
 
-}  // namespace common
+}  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/common/address.h b/gd/hci/address.h
similarity index 83%
rename from gd/common/address.h
rename to gd/hci/address.h
index 0036a59..3bc507f 100644
--- a/gd/common/address.h
+++ b/gd/hci/address.h
@@ -18,10 +18,11 @@
 
 #pragma once
 
+#include <cstring>
 #include <string>
 
 namespace bluetooth {
-namespace common {
+namespace hci {
 
 class Address final {
  public:
@@ -77,5 +78,17 @@
   return os;
 }
 
-}  // namespace common
+}  // namespace hci
 }  // namespace bluetooth
+
+namespace std {
+template <>
+struct hash<bluetooth::hci::Address> {
+  std::size_t operator()(const bluetooth::hci::Address& val) const {
+    static_assert(sizeof(uint64_t) >= bluetooth::hci::Address::kLength);
+    uint64_t int_addr = 0;
+    memcpy(reinterpret_cast<uint8_t*>(&int_addr), val.address, bluetooth::hci::Address::kLength);
+    return std::hash<uint64_t>{}(int_addr);
+  }
+};
+}  // namespace std
\ No newline at end of file
diff --git a/gd/common/address_unittest.cc b/gd/hci/address_unittest.cc
similarity index 82%
rename from gd/common/address_unittest.cc
rename to gd/hci/address_unittest.cc
index cdecce3..17ecd3a 100644
--- a/gd/common/address_unittest.cc
+++ b/gd/hci/address_unittest.cc
@@ -16,11 +16,13 @@
  *
  ******************************************************************************/
 
+#include <unordered_map>
+
 #include <gtest/gtest.h>
 
-#include "common/address.h"
+#include "hci/address.h"
 
-using bluetooth::common::Address;
+using bluetooth::hci::Address;
 
 static const char* test_addr = "bc:9a:78:56:34:12";
 static const char* test_addr2 = "21:43:65:87:a9:cb";
@@ -197,3 +199,34 @@
   EXPECT_TRUE(Address::FromString(address, addr));
   EXPECT_EQ(addr.ToString(), address);
 }
+
+TEST(AddressTest, BdAddrSameValueSameOrder) {
+  Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  // Test if two addresses with same byte value have the same hash
+  struct std::hash<bluetooth::hci::Address> hasher;
+  EXPECT_EQ(hasher(addr1), hasher(addr2));
+  // Test if two addresses with the same hash and the same value, they will
+  // still map to the same value
+  std::unordered_map<Address, int> data = {};
+  data[addr1] = 5;
+  data[addr2] = 8;
+  EXPECT_EQ(data[addr1], data[addr2]);
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesZeroAddr) {
+  Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  struct std::hash<Address> hasher;
+  EXPECT_NE(hasher(addr1), hasher(Address::kEmpty));
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesFullAddr) {
+  Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  struct std::hash<Address> hasher;
+  EXPECT_NE(hasher(addr1), hasher(Address::kAny));
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesZeroAndFullAddr) {
+  struct std::hash<Address> hasher;
+  EXPECT_NE(hasher(Address::kEmpty), hasher(Address::kAny));
+}
diff --git a/gd/hci/address_with_type.h b/gd/hci/address_with_type.h
new file mode 100644
index 0000000..bed2cf2
--- /dev/null
+++ b/gd/hci/address_with_type.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ *  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 <sstream>
+#include <string>
+#include <utility>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AddressWithType final {
+ public:
+  AddressWithType(Address address, AddressType address_type) : address_(address), address_type_(address_type) {}
+
+  explicit AddressWithType() : address_(Address::kEmpty), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS) {}
+
+  inline Address GetAddress() const {
+    return address_;
+  }
+
+  inline AddressType GetAddressType() const {
+    return address_type_;
+  }
+
+  bool operator<(const AddressWithType& rhs) const {
+    return address_ < rhs.address_ && address_type_ < rhs.address_type_;
+  }
+  bool operator==(const AddressWithType& rhs) const {
+    return address_ == rhs.address_ && address_type_ == rhs.address_type_;
+  }
+  bool operator>(const AddressWithType& rhs) const {
+    return (rhs < *this);
+  }
+  bool operator<=(const AddressWithType& rhs) const {
+    return !(*this > rhs);
+  }
+  bool operator>=(const AddressWithType& rhs) const {
+    return !(*this < rhs);
+  }
+  bool operator!=(const AddressWithType& rhs) const {
+    return !(*this == rhs);
+  }
+
+  std::string ToString() const {
+    std::stringstream ss;
+    ss << address_ << "[" << AddressTypeText(address_type_) << "]";
+    return ss.str();
+  }
+
+ private:
+  Address address_;
+  AddressType address_type_;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const AddressWithType& a) {
+  os << a.ToString();
+  return os;
+}
+
+}  // namespace hci
+}  // namespace bluetooth
+
+namespace std {
+template <>
+struct hash<bluetooth::hci::AddressWithType> {
+  std::size_t operator()(const bluetooth::hci::AddressWithType& val) const {
+    static_assert(sizeof(uint64_t) >= (sizeof(bluetooth::hci::Address) + sizeof(bluetooth::hci::AddressType)));
+    uint64_t int_addr = 0;
+    memcpy(reinterpret_cast<uint8_t*>(&int_addr), val.GetAddress().address, sizeof(bluetooth::hci::Address));
+    bluetooth::hci::AddressType address_type = val.GetAddressType();
+    memcpy(reinterpret_cast<uint8_t*>(&int_addr) + sizeof(bluetooth::hci::Address), &address_type,
+           sizeof(address_type));
+    return std::hash<uint64_t>{}(int_addr);
+  }
+};
+}  // namespace std
\ No newline at end of file
diff --git a/gd/hci/address_with_type_test.cc b/gd/hci/address_with_type_test.cc
new file mode 100644
index 0000000..f1e5a60
--- /dev/null
+++ b/gd/hci/address_with_type_test.cc
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ *  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 <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "hci/address.h"
+#include "hci/address_with_type.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hci {
+
+TEST(AddressWithTypeTest, AddressWithTypeSameValueSameOrder) {
+  Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  AddressType type1 = AddressType::PUBLIC_DEVICE_ADDRESS;
+  AddressWithType address_with_type_1(addr1, type1);
+  Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  AddressType type2 = AddressType::PUBLIC_DEVICE_ADDRESS;
+  AddressWithType address_with_type_2(addr2, type2);
+  // Test if two address with type with same byte value have the same hash
+  struct std::hash<bluetooth::hci::AddressWithType> hasher;
+  EXPECT_EQ(hasher(address_with_type_1), hasher(address_with_type_2));
+  // Test if two address with type with the same hash and the same value, they will
+  // still map to the same value
+  std::unordered_map<AddressWithType, int> data = {};
+  data[address_with_type_1] = 5;
+  data[address_with_type_2] = 8;
+  EXPECT_EQ(data[address_with_type_1], data[address_with_type_2]);
+}
+
+TEST(AddressWithTypeTest, HashDifferentDiffAddrSameType) {
+  Address addr{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  AddressType type = AddressType::PUBLIC_IDENTITY_ADDRESS;
+  AddressWithType address_with_type(addr, type);
+  struct std::hash<AddressWithType> hasher;
+  EXPECT_NE(hasher(address_with_type), hasher(AddressWithType(Address::kEmpty, AddressType::PUBLIC_IDENTITY_ADDRESS)));
+}
+
+TEST(AddressWithTypeTest, HashDifferentSameAddressDiffType) {
+  Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  AddressType type1 = AddressType::PUBLIC_DEVICE_ADDRESS;
+  AddressWithType address_with_type_1(addr1, type1);
+  Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  AddressType type2 = AddressType::PUBLIC_IDENTITY_ADDRESS;
+  AddressWithType address_with_type_2(addr2, type2);
+  struct std::hash<bluetooth::hci::AddressWithType> hasher;
+  EXPECT_NE(hasher(address_with_type_1), hasher(address_with_type_2));
+}
+
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/cert/api.proto b/gd/hci/cert/api.proto
index 32b4bf1..cf47743 100644
--- a/gd/hci/cert/api.proto
+++ b/gd/hci/cert/api.proto
@@ -6,7 +6,6 @@
 import "facade/common.proto";
 
 service AclManagerCert {
-  rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
   rpc SetPageScanMode(PageScanMode) returns (google.protobuf.Empty) {}
   rpc SetIncomingConnectionPolicy(IncomingConnectionPolicy) returns (google.protobuf.Empty) {}
   rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
diff --git a/gd/hci/cert/cert.cc b/gd/hci/cert/cert.cc
index 14c989b..3ca100f 100644
--- a/gd/hci/cert/cert.cc
+++ b/gd/hci/cert/cert.cc
@@ -24,6 +24,7 @@
 #include "common/blocking_queue.h"
 #include "grpc/grpc_event_stream.h"
 #include "hci/cert/api.grpc.pb.h"
+#include "hci/classic_security_manager.h"
 #include "hci/controller.h"
 #include "hci/hci_layer.h"
 #include "hci/hci_packets.h"
@@ -57,6 +58,15 @@
     hci_layer_->RegisterEventHandler(EventCode::CONNECTION_REQUEST,
                                      Bind(&AclManagerCertService::on_incoming_connection, common::Unretained(this)),
                                      handler_);
+    hci_layer_->RegisterEventHandler(
+        EventCode::CONNECTION_PACKET_TYPE_CHANGED,
+        Bind(&AclManagerCertService::on_connection_packet_type_changed, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::QOS_SETUP_COMPLETE,
+                                     Bind(&AclManagerCertService::on_qos_setup_complete, common::Unretained(this)),
+                                     handler_);
+    hci_layer_->RegisterEventHandler(EventCode::ROLE_CHANGE,
+                                     Bind(&AclManagerCertService::on_role_change, common::Unretained(this)), handler_);
+
     controller_->RegisterCompletedAclPacketsCallback(common::Bind([](uint16_t, uint16_t) { /* TODO check */ }),
                                                      handler_);
     acl_queue_end_->RegisterDequeue(handler_,
@@ -125,7 +135,7 @@
   void on_incoming_connection(EventPacketView packet) {
     ConnectionRequestView request = ConnectionRequestView::Create(packet);
     ASSERT(request.IsValid());
-    common::Address address = request.GetBdAddr();
+    Address address = request.GetBdAddr();
     if (accepted_devices_.find(address) != accepted_devices_.end()) {
       auto role = AcceptConnectionRequestRole::BECOME_MASTER;  // We prefer to be master
       hci_layer_->EnqueueCommand(AcceptConnectionRequestBuilder::Create(address, role),
@@ -138,15 +148,17 @@
     }
   }
 
-  using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
-
-  ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-                                  ::bluetooth::facade::BluetoothAddress* response) override {
-    auto address = controller_->GetControllerMacAddress().ToString();
-    response->set_address(address);
-    return ::grpc::Status::OK;
+  void on_connection_packet_type_changed(EventPacketView packet) { /*TODO*/
   }
 
+  void on_qos_setup_complete(EventPacketView packet) { /*TODO*/
+  }
+
+  void on_role_change(EventPacketView packet) { /*TODO*/
+  }
+
+  using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
+
   ::grpc::Status SetPageScanMode(::grpc::ServerContext* context, const ::bluetooth::hci::cert::PageScanMode* request,
                                  ::google::protobuf::Empty* response) override {
     ScanEnable scan_enable = request->enabled() ? ScanEnable::PAGE_SCAN_ONLY : ScanEnable::NO_SCANS;
@@ -165,8 +177,8 @@
                                              const ::bluetooth::hci::cert::IncomingConnectionPolicy* request,
                                              ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
-    common::Address peer;
-    ASSERT(common::Address::FromString(request->remote().address(), peer));
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
     if (request->accepted()) {
       accepted_devices_.insert(peer);
     } else {
@@ -185,8 +197,8 @@
     ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
     CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
 
-    common::Address peer;
-    ASSERT(common::Address::FromString(remote->address(), peer));
+    Address peer;
+    ASSERT(Address::FromString(remote->address(), peer));
     std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
         peer, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);
 
@@ -202,8 +214,8 @@
   ::grpc::Status Disconnect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
                             ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
-    common::Address peer;
-    common::Address::FromString(request->address(), peer);
+    Address peer;
+    Address::FromString(request->address(), peer);
     uint16_t handle = find_connected_device_handle_by_address(peer);
     if (handle == kInvalidHandle) {
       return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
@@ -218,14 +230,14 @@
 
   ::grpc::Status SendAclData(::grpc::ServerContext* context, const AclData* request,
                              ::google::protobuf::Empty* response) override {
-    common::Address peer;
-    common::Address::FromString(request->remote().address(), peer);
+    Address peer;
+    Address::FromString(request->remote().address(), peer);
     auto handle = find_connected_device_handle_by_address(peer);
     if (handle == kInvalidHandle) {
       return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
     }
 
-    constexpr PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
+    constexpr PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
     constexpr BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
     std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
     auto req_string = request->payload();
@@ -263,12 +275,12 @@
   common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* acl_queue_end_;
   os::EnqueueBuffer<AclPacketBuilder> acl_enqueue_buffer_{acl_queue_end_};
   mutable std::mutex mutex_;
-  std::set<common::Address> accepted_devices_;
-  std::map<uint16_t /* handle */, common::Address> connected_devices_;
+  std::set<Address> accepted_devices_;
+  std::map<uint16_t /* handle */, Address> connected_devices_;
 
   constexpr static uint16_t kInvalidHandle = 0xffff;
 
-  uint16_t find_connected_device_handle_by_address(common::Address address) {
+  uint16_t find_connected_device_handle_by_address(Address address) {
     for (auto device : connected_devices_) {
       if (device.second == address) {
         return device.first;
@@ -321,6 +333,7 @@
   ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
   list->add<Controller>();
   list->add<HciLayer>();
+  list->add<ClassicSecurityManager>();
 }
 
 void AclManagerCertModule::Start() {
diff --git a/gd/hci/cert/simple_hci_test.py b/gd/hci/cert/simple_hci_test.py
index 493bff8..5cfd0ee 100644
--- a/gd/hci/cert/simple_hci_test.py
+++ b/gd/hci/cert/simple_hci_test.py
@@ -57,14 +57,15 @@
             hci_cert_pb2.PageScanMode(enabled=True)
         )
 
-        dut_address = self.device_under_test.hci.ReadLocalAddress(empty_pb2.Empty()).address
+        dut_address = self.device_under_test.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
         self.device_under_test.address = dut_address
-        cert_address = self.cert_device.hci.ReadLocalAddress(empty_pb2.Empty()).address
+        cert_address = self.cert_device.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
         self.cert_device.address = cert_address
 
         self.dut_connection_complete_stream = self.device_under_test.hci.connection_complete_stream
         self.dut_disconnection_stream = self.device_under_test.hci.disconnection_stream
         self.dut_connection_failed_stream = self.device_under_test.hci.connection_failed_stream
+        self.dut_command_complete_stream = self.device_under_test.hci_classic_security.command_complete_stream
 
         self.dut_address = common_pb2.BluetoothAddress(
             address=self.device_under_test.address)
@@ -95,7 +96,7 @@
         self.dut_connection_complete_stream.subscribe()
         self.device_under_test.hci.Connect(self.cert_address)
         self.dut_connection_complete_stream.assert_event_occurs(
-            lambda event: event.remote.address == self.cert_device.address
+            lambda event: self._get_handle(event)
         )
         self.dut_connection_complete_stream.unsubscribe()
 
@@ -106,6 +107,12 @@
             lambda event: event.remote.address == self.cert_device.address
         )
 
+    def _get_handle(self, event):
+        if event.remote.address == self.cert_device.address:
+            self.connection_handle = event.connection_handle
+            return True
+        return False
+
     def test_connect_disconnect_send_acl(self):
         self._connect_from_dut()
 
@@ -146,3 +153,194 @@
             lambda event : event.remote == self.cert_address
         )
         self.dut_connection_failed_stream.unsubscribe()
+
+    def test_send_classic_security_command(self):
+        self._connect_from_dut()
+        self.dut_command_complete_stream.subscribe()
+
+        self.device_under_test.hci.AuthenticationRequested(self.cert_address)
+
+        # Link request
+        self.device_under_test.hci_classic_security.LinkKeyRequestNegativeReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x040c
+        )
+
+        # Pin code request
+        message = hci_facade_pb2.PinCodeRequestReplyMessage(
+            remote=self.cert_address,
+            len=4,
+            pin_code=bytes("1234", encoding = "ASCII")
+        )
+        self.device_under_test.hci_classic_security.PinCodeRequestReply(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x040d
+        )
+        self.device_under_test.hci_classic_security.PinCodeRequestNegativeReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x040e
+        )
+
+        # IO capability request
+        message = hci_facade_pb2.IoCapabilityRequestReplyMessage(
+            remote=self.cert_address,
+            io_capability=0,
+            oob_present=0,
+            authentication_requirements=0
+        )
+        self.device_under_test.hci_classic_security.IoCapabilityRequestReply(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x042b
+        )
+
+        # message = hci_facade_pb2.IoCapabilityRequestNegativeReplyMessage(
+        #     remote=self.cert_address,
+        #     reason=1
+        # )
+        # # link_layer_controller.cc(447)] Check failed: security_manager_.GetAuthenticationAddress() == peer
+        # self.device_under_test.hci_classic_security.IoCapabilityRequestNegativeReply(message)
+
+        # User confirm request
+        self.device_under_test.hci_classic_security.UserConfirmationRequestReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x042c
+        )
+
+        message = hci_facade_pb2.LinkKeyRequestReplyMessage(
+            remote=self.cert_address,
+            link_key=bytes("4C68384139F574D836BCF34E9DFB01BF", encoding = "ASCII")
+        )
+        self.device_under_test.hci_classic_security.LinkKeyRequestReply(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x040b
+        )
+
+        self.device_under_test.hci_classic_security.UserConfirmationRequestNegativeReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x042d
+        )
+
+        # User passkey request
+        message = hci_facade_pb2.UserPasskeyRequestReplyMessage(
+            remote=self.cert_address,
+            passkey=999999,
+        )
+        self.device_under_test.hci_classic_security.UserPasskeyRequestReply(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x042e
+        )
+
+        self.device_under_test.hci_classic_security.UserPasskeyRequestNegativeReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x042f
+        )
+
+        # Remote OOB data request
+        message = hci_facade_pb2.RemoteOobDataRequestReplyMessage(
+            remote=self.cert_address,
+            c=b'\x19\x20\x21\x22\x23\x24\x25\x26\x19\x20\x21\x22\x23\x24\x25\x26',
+            r=b'\x30\x31\x32\x33\x34\x35\x36\x37\x30\x31\x32\x33\x34\x35\x36\x37',
+        )
+        self.device_under_test.hci_classic_security.RemoteOobDataRequestReply(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0430
+        )
+        self.device_under_test.hci_classic_security.RemoteOobDataRequestNegativeReply(self.cert_address)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0433
+        )
+
+        # Read/Write/Delete link key
+        message = hci_facade_pb2.ReadStoredLinkKeyMessage(
+            remote=self.cert_address,
+            read_all_flag = 0,
+        )
+        self.device_under_test.hci_classic_security.ReadStoredLinkKey(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c0d
+        )
+
+        message = hci_facade_pb2.WriteStoredLinkKeyMessage(
+            num_keys_to_write=1,
+            remote=self.cert_address,
+            link_keys=bytes("4C68384139F574D836BCF34E9DFB01BF", encoding = "ASCII"),
+        )
+        self.device_under_test.hci_classic_security.WriteStoredLinkKey(message)
+
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c11
+        )
+
+        message = hci_facade_pb2.DeleteStoredLinkKeyMessage(
+            remote=self.cert_address,
+            delete_all_flag = 0,
+        )
+        self.device_under_test.hci_classic_security.DeleteStoredLinkKey(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c12
+        )
+
+        # Refresh Encryption Key
+        message = hci_facade_pb2.RefreshEncryptionKeyMessage(
+            connection_handle=self.connection_handle,
+        )
+        self.device_under_test.hci_classic_security.RefreshEncryptionKey(message)
+
+        # Read/Write Simple Pairing Mode
+        self.device_under_test.hci_classic_security.ReadSimplePairingMode(empty_pb2.Empty())
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c55
+        )
+
+        message = hci_facade_pb2.WriteSimplePairingModeMessage(
+            simple_pairing_mode=1,
+        )
+        self.device_under_test.hci_classic_security.WriteSimplePairingMode(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c56
+        )
+
+        # Read local oob data
+        self.device_under_test.hci_classic_security.ReadLocalOobData(empty_pb2.Empty())
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c57
+        )
+
+        # Send keypress notification
+        message = hci_facade_pb2.SendKeypressNotificationMessage(
+            remote=self.cert_address,
+            notification_type=1,
+        )
+        self.device_under_test.hci_classic_security.SendKeypressNotification(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c60
+        )
+
+        # Read local oob extended data
+        self.device_under_test.hci_classic_security.ReadLocalOobExtendedData(empty_pb2.Empty())
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x0c7d
+        )
+
+        # Read Encryption key size
+        message = hci_facade_pb2.ReadEncryptionKeySizeMessage(
+            connection_handle=self.connection_handle,
+        )
+        self.device_under_test.hci_classic_security.ReadEncryptionKeySize(message)
+        self.dut_command_complete_stream.assert_event_occurs(
+            lambda event: event.command_opcode == 0x1408
+        )
+
+        self.dut_command_complete_stream.unsubscribe()
+        self._disconnect_from_dut()
+
+    def test_interal_hci_command(self):
+        self._connect_from_dut()
+        self.device_under_test.hci.TestInternalHciCommands(empty_pb2.Empty())
+        self.device_under_test.hci.TestInternalHciLeCommands(empty_pb2.Empty())
+        self._disconnect_from_dut()
+
+    def test_classic_connection_management_command(self):
+        self._connect_from_dut()
+        self.device_under_test.hci.TestClassicConnectionManagementCommands(self.cert_address)
+        self._disconnect_from_dut()
\ No newline at end of file
diff --git a/gd/common/class_of_device.cc b/gd/hci/class_of_device.cc
similarity index 92%
rename from gd/common/class_of_device.cc
rename to gd/hci/class_of_device.cc
index 8d7ff68..36dd292 100644
--- a/gd/common/class_of_device.cc
+++ b/gd/hci/class_of_device.cc
@@ -26,7 +26,7 @@
 #include "os/log.h"
 
 namespace bluetooth {
-namespace common {
+namespace hci {
 
 static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
 
@@ -36,11 +36,10 @@
 
 std::string ClassOfDevice::ToString() const {
   char buffer[] = "000-0-00";
-  std::snprintf(&buffer[0], sizeof(buffer),
-      "%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f, cod[0]);
+  std::snprintf(&buffer[0], sizeof(buffer), "%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4,
+                cod[1] & 0x0f, cod[0]);
   std::string str(buffer);
   return str;
-
 }
 
 bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
@@ -94,5 +93,5 @@
   ClassOfDevice tmp;
   return ClassOfDevice::FromString(cod, tmp);
 }
-}  // namespace common
+}  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/common/class_of_device.h b/gd/hci/class_of_device.h
similarity index 92%
rename from gd/common/class_of_device.h
rename to gd/hci/class_of_device.h
index 983f128..b44a45e 100644
--- a/gd/common/class_of_device.h
+++ b/gd/hci/class_of_device.h
@@ -21,7 +21,7 @@
 #include <string>
 
 namespace bluetooth {
-namespace common {
+namespace hci {
 
 class ClassOfDevice final {
  public:
@@ -36,6 +36,10 @@
     return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
   }
 
+  bool operator!=(const ClassOfDevice& rhs) const {
+    return std::memcmp(cod, rhs.cod, sizeof(cod)) != 0;
+  }
+
   std::string ToString() const;
 
   // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
@@ -55,5 +59,5 @@
   return os;
 }
 
-}  // namespace common
+}  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/common/class_of_device_unittest.cc b/gd/hci/class_of_device_unittest.cc
similarity index 97%
rename from gd/common/class_of_device_unittest.cc
rename to gd/hci/class_of_device_unittest.cc
index abd4a59..85472dd 100644
--- a/gd/common/class_of_device_unittest.cc
+++ b/gd/hci/class_of_device_unittest.cc
@@ -18,9 +18,9 @@
 
 #include <gtest/gtest.h>
 
-#include "common/class_of_device.h"
+#include "hci/class_of_device.h"
 
-using bluetooth::common::ClassOfDevice;
+using bluetooth::hci::ClassOfDevice;
 
 static const char* test_class = "efc-d-ab";
 static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
diff --git a/gd/hci/classic_device.h b/gd/hci/classic_device.h
new file mode 100644
index 0000000..53ff0ba
--- /dev/null
+++ b/gd/hci/classic_device.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ *  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 "hci/device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * A device representing a CLASSIC device.
+ *
+ * <p>This can be a CLASSIC only or a piece of a DUAL MODE device.
+ */
+class ClassicDevice : public Device {
+ protected:
+  friend class DeviceDatabase;
+  explicit ClassicDevice(Address address) : Device(address, DeviceType::CLASSIC) {}
+};
+
+}  // namespace bluetooth::hci
diff --git a/gd/hci/classic_security_manager.cc b/gd/hci/classic_security_manager.cc
new file mode 100644
index 0000000..8425ae6
--- /dev/null
+++ b/gd/hci/classic_security_manager.cc
@@ -0,0 +1,368 @@
+/*
+ * 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 "classic_security_manager.h"
+
+#include <future>
+#include <set>
+#include <utility>
+#include "os/log.h"
+
+#include "acl_manager.h"
+#include "common/bidi_queue.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace hci {
+
+using common::Bind;
+using common::BindOnce;
+
+struct ClassicSecurityManager::impl {
+  impl(ClassicSecurityManager& classic_security_manager) : classic_security_manager_(classic_security_manager) {}
+
+  void Start() {
+    hci_layer_ = classic_security_manager_.GetDependency<HciLayer>();
+    handler_ = classic_security_manager_.GetHandler();
+    hci_layer_->RegisterEventHandler(EventCode::IO_CAPABILITY_REQUEST,
+                                     Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::LINK_KEY_REQUEST,
+                                     Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::PIN_CODE_REQUEST,
+                                     Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE,
+                                     Bind(&impl::on_complete_event, common::Unretained(this)), handler_);
+  }
+
+  void Stop() {
+    hci_layer_->UnregisterEventHandler(EventCode::IO_CAPABILITY_REQUEST);
+    handler_ = nullptr;
+    hci_layer_ = nullptr;
+  }
+
+  void handle_register_callbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler) {
+    ASSERT(client_callbacks_ == nullptr);
+    ASSERT(client_handler_ == nullptr);
+    client_callbacks_ = callbacks;
+    client_handler_ = handler;
+  }
+
+  void link_key_request_reply(Address address, common::LinkKey link_key) {
+    std::array<uint8_t, 16> link_key_array;
+    std::copy(std::begin(link_key.link_key), std::end(link_key.link_key), std::begin(link_key_array));
+
+    std::unique_ptr<LinkKeyRequestReplyBuilder> packet = LinkKeyRequestReplyBuilder::Create(address, link_key_array);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void link_key_request_negative_reply(Address address) {
+    std::unique_ptr<LinkKeyRequestNegativeReplyBuilder> packet = LinkKeyRequestNegativeReplyBuilder::Create(address);
+
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void pin_code_request_reply(Address address, uint8_t len, std::string pin_code) {
+    ASSERT(len > 0 && len <= 16 && pin_code.length() == len);
+    // fill remaining char with 0
+    pin_code.append(std::string(16 - len, '0'));
+    std::array<uint8_t, 16> pin_code_array;
+    std::copy(std::begin(pin_code), std::end(pin_code), std::begin(pin_code_array));
+
+    std::unique_ptr<PinCodeRequestReplyBuilder> packet =
+        PinCodeRequestReplyBuilder::Create(address, len, pin_code_array);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void pin_code_request_negative_reply(Address address) {
+    std::unique_ptr<PinCodeRequestNegativeReplyBuilder> packet = PinCodeRequestNegativeReplyBuilder::Create(address);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void io_capability_request_reply(Address address, IoCapability io_capability, OobDataPresent oob_present,
+                                   AuthenticationRequirements authentication_requirements) {
+    std::unique_ptr<IoCapabilityRequestReplyBuilder> packet =
+        IoCapabilityRequestReplyBuilder::Create(address, io_capability, oob_present, authentication_requirements);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void io_capability_request_negative_reply(Address address, ErrorCode reason) {
+    std::unique_ptr<IoCapabilityRequestNegativeReplyBuilder> packet =
+        IoCapabilityRequestNegativeReplyBuilder::Create(address, reason);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void user_confirmation_request_reply(Address address) {
+    std::unique_ptr<UserConfirmationRequestReplyBuilder> packet = UserConfirmationRequestReplyBuilder::Create(address);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void user_confirmation_request_negative_reply(Address address) {
+    std::unique_ptr<UserConfirmationRequestNegativeReplyBuilder> packet =
+        UserConfirmationRequestNegativeReplyBuilder::Create(address);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void user_passkey_request_reply(Address address, uint32_t passkey) {
+    ASSERT(passkey <= 999999);
+    std::unique_ptr<UserPasskeyRequestReplyBuilder> packet = UserPasskeyRequestReplyBuilder::Create(address, passkey);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void user_passkey_request_negative_reply(Address address) {
+    std::unique_ptr<UserPasskeyRequestNegativeReplyBuilder> packet =
+        UserPasskeyRequestNegativeReplyBuilder::Create(address);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void remote_oob_data_request_reply(Address address, std::array<uint8_t, 16> c, std::array<uint8_t, 16> r) {
+    std::unique_ptr<RemoteOobDataRequestReplyBuilder> packet = RemoteOobDataRequestReplyBuilder::Create(address, c, r);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void remote_oob_data_request_negative_reply(Address address) {
+    std::unique_ptr<RemoteOobDataRequestNegativeReplyBuilder> packet =
+        RemoteOobDataRequestNegativeReplyBuilder::Create(address);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void read_stored_link_key(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag) {
+    std::unique_ptr<ReadStoredLinkKeyBuilder> packet = ReadStoredLinkKeyBuilder::Create(address, read_all_flag);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void write_stored_link_key(std::vector<KeyAndAddress> keys) {
+    std::unique_ptr<WriteStoredLinkKeyBuilder> packet = WriteStoredLinkKeyBuilder::Create(keys);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void delete_stored_link_key(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag) {
+    std::unique_ptr<DeleteStoredLinkKeyBuilder> packet = DeleteStoredLinkKeyBuilder::Create(address, delete_all_flag);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void refresh_encryption_key(uint16_t connection_handle) {
+    std::unique_ptr<RefreshEncryptionKeyBuilder> packet = RefreshEncryptionKeyBuilder::Create(connection_handle);
+    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+                               handler_);
+  }
+
+  void read_simple_pairing_mode() {
+    std::unique_ptr<ReadSimplePairingModeBuilder> packet = ReadSimplePairingModeBuilder::Create();
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void write_simple_pairing_mode(Enable connection_handle) {
+    std::unique_ptr<WriteSimplePairingModeBuilder> packet = WriteSimplePairingModeBuilder::Create(connection_handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void read_local_oob_data() {
+    std::unique_ptr<ReadLocalOobDataBuilder> packet = ReadLocalOobDataBuilder::Create();
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void send_keypress_notification(Address address, KeypressNotificationType notification_type) {
+    std::unique_ptr<SendKeypressNotificationBuilder> packet =
+        SendKeypressNotificationBuilder::Create(address, notification_type);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void read_local_oob_extended_data() {
+    std::unique_ptr<ReadLocalOobExtendedDataBuilder> packet = ReadLocalOobExtendedDataBuilder::Create();
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  void read_encryption_key_size(uint16_t connection_handle) {
+    std::unique_ptr<ReadEncryptionKeySizeBuilder> packet = ReadEncryptionKeySizeBuilder::Create(connection_handle);
+    hci_layer_->EnqueueCommand(std::move(packet),
+                               common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+  }
+
+  // TODO remove
+  void on_request_event(EventPacketView packet) {
+    EventCode event_code = packet.GetEventCode();
+    LOG_DEBUG("receive request %d", (uint8_t)event_code);
+  }
+
+  // TODO remove
+  void on_complete_event(EventPacketView packet) {
+    EventCode event_code = packet.GetEventCode();
+    LOG_DEBUG("receive complete event %d", (uint8_t)event_code);
+  }
+
+  void on_command_complete(CommandCompleteView status) {
+    if (client_handler_ != nullptr) {
+      client_handler_->Post(common::BindOnce(&ClassicSecurityCommandCallbacks::OnCommandComplete,
+                                             common::Unretained(client_callbacks_), status));
+    }
+  }
+
+  ClassicSecurityManager& classic_security_manager_;
+
+  Controller* controller_ = nullptr;
+
+  HciLayer* hci_layer_ = nullptr;
+  os::Handler* handler_ = nullptr;
+  ClassicSecurityCommandCallbacks* client_callbacks_ = nullptr;
+  os::Handler* client_handler_ = nullptr;
+};
+
+ClassicSecurityManager::ClassicSecurityManager() : pimpl_(std::make_unique<impl>(*this)) {}
+
+bool ClassicSecurityManager::RegisterCallbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler) {
+  ASSERT(callbacks != nullptr && handler != nullptr);
+  GetHandler()->Post(common::BindOnce(&impl::handle_register_callbacks, common::Unretained(pimpl_.get()),
+                                      common::Unretained(callbacks), common::Unretained(handler)));
+  return true;
+}
+
+void ClassicSecurityManager::LinkKeyRequestReply(Address address, common::LinkKey link_key) {
+  GetHandler()->Post(BindOnce(&impl::link_key_request_reply, common::Unretained(pimpl_.get()), address, link_key));
+}
+
+void ClassicSecurityManager::LinkKeyRequestNegativeReply(Address address) {
+  GetHandler()->Post(BindOnce(&impl::link_key_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::PinCodeRequestReply(Address address, uint8_t len, std::string pin_code) {
+  GetHandler()->Post(BindOnce(&impl::pin_code_request_reply, common::Unretained(pimpl_.get()), address, len, pin_code));
+}
+
+void ClassicSecurityManager::PinCodeRequestNegativeReply(Address address) {
+  GetHandler()->Post(BindOnce(&impl::pin_code_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::IoCapabilityRequestReply(Address address, IoCapability io_capability,
+                                                      OobDataPresent oob_present,
+                                                      AuthenticationRequirements authentication_requirements) {
+  GetHandler()->Post(BindOnce(&impl::io_capability_request_reply, common::Unretained(pimpl_.get()), address,
+                              io_capability, oob_present, authentication_requirements));
+}
+
+void ClassicSecurityManager::IoCapabilityRequestNegativeReply(Address address, ErrorCode reason) {
+  GetHandler()->Post(
+      BindOnce(&impl::io_capability_request_negative_reply, common::Unretained(pimpl_.get()), address, reason));
+}
+
+void ClassicSecurityManager::UserConfirmationRequestReply(Address address) {
+  GetHandler()->Post(BindOnce(&impl::user_confirmation_request_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::UserConfirmationRequestNegativeReply(Address address) {
+  GetHandler()->Post(
+      BindOnce(&impl::user_confirmation_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::UserPasskeyRequestReply(bluetooth::hci::Address address, uint32_t passkey) {
+  GetHandler()->Post(BindOnce(&impl::user_passkey_request_reply, common::Unretained(pimpl_.get()), address, passkey));
+}
+
+void ClassicSecurityManager::UserPasskeyRequestNegativeReply(Address address) {
+  GetHandler()->Post(BindOnce(&impl::user_passkey_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::RemoteOobDataRequestReply(Address address, std::array<uint8_t, 16> c,
+                                                       std::array<uint8_t, 16> r) {
+  GetHandler()->Post(BindOnce(&impl::remote_oob_data_request_reply, common::Unretained(pimpl_.get()), address, c, r));
+}
+
+void ClassicSecurityManager::RemoteOobDataRequestNegativeReply(Address address) {
+  GetHandler()->Post(
+      BindOnce(&impl::remote_oob_data_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::ReadStoredLinkKey(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag) {
+  GetHandler()->Post(BindOnce(&impl::read_stored_link_key, common::Unretained(pimpl_.get()), address, read_all_flag));
+}
+
+void ClassicSecurityManager::WriteStoredLinkKey(std::vector<KeyAndAddress> keys) {
+  GetHandler()->Post(BindOnce(&impl::write_stored_link_key, common::Unretained(pimpl_.get()), keys));
+}
+
+void ClassicSecurityManager::DeleteStoredLinkKey(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag) {
+  GetHandler()->Post(
+      BindOnce(&impl::delete_stored_link_key, common::Unretained(pimpl_.get()), address, delete_all_flag));
+}
+
+void ClassicSecurityManager::RefreshEncryptionKey(uint16_t connection_handle) {
+  GetHandler()->Post(BindOnce(&impl::refresh_encryption_key, common::Unretained(pimpl_.get()), connection_handle));
+}
+void ClassicSecurityManager::ReadSimplePairingMode() {
+  GetHandler()->Post(BindOnce(&impl::read_simple_pairing_mode, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::WriteSimplePairingMode(Enable simple_pairing_mode) {
+  GetHandler()->Post(BindOnce(&impl::write_simple_pairing_mode, common::Unretained(pimpl_.get()), simple_pairing_mode));
+}
+
+void ClassicSecurityManager::ReadLocalOobData() {
+  GetHandler()->Post(BindOnce(&impl::read_local_oob_data, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::SendKeypressNotification(Address address, KeypressNotificationType notification_type) {
+  GetHandler()->Post(
+      BindOnce(&impl::send_keypress_notification, common::Unretained(pimpl_.get()), address, notification_type));
+}
+
+void ClassicSecurityManager::ReadLocalOobExtendedData() {
+  GetHandler()->Post(BindOnce(&impl::read_local_oob_extended_data, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::ReadEncryptionKeySize(uint16_t connection_handle) {
+  GetHandler()->Post(BindOnce(&impl::read_encryption_key_size, common::Unretained(pimpl_.get()), connection_handle));
+}
+
+void ClassicSecurityManager::ListDependencies(ModuleList* list) {
+  list->add<HciLayer>();
+}
+
+void ClassicSecurityManager::Start() {
+  pimpl_->Start();
+}
+
+void ClassicSecurityManager::Stop() {
+  pimpl_->Stop();
+}
+
+std::string ClassicSecurityManager::ToString() const {
+  return "Classic Security Manager";
+}
+
+const ModuleFactory ClassicSecurityManager::Factory = ModuleFactory([]() { return new ClassicSecurityManager(); });
+
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/classic_security_manager.h b/gd/hci/classic_security_manager.h
new file mode 100644
index 0000000..22b4ae1
--- /dev/null
+++ b/gd/hci/classic_security_manager.h
@@ -0,0 +1,81 @@
+/*
+ * 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 "common/link_key.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class ClassicSecurityCommandCallbacks {
+ public:
+  virtual ~ClassicSecurityCommandCallbacks() = default;
+  // Invoked when controller sends Command Complete event
+  virtual void OnCommandComplete(CommandCompleteView status) = 0;
+};
+
+class ClassicSecurityManager : public Module {
+ public:
+  ClassicSecurityManager();
+
+  bool RegisterCallbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler);
+
+  void LinkKeyRequestReply(Address address, common::LinkKey link_key);
+  void LinkKeyRequestNegativeReply(Address address);
+  void PinCodeRequestReply(Address address, uint8_t len, std::string pin_code);
+  void PinCodeRequestNegativeReply(Address address);
+  void IoCapabilityRequestReply(Address address, IoCapability io_capability, OobDataPresent oob_present,
+                                AuthenticationRequirements authentication_requirements);
+  void IoCapabilityRequestNegativeReply(Address address, ErrorCode reason);
+  void UserConfirmationRequestReply(Address address);
+  void UserConfirmationRequestNegativeReply(Address address);
+  void UserPasskeyRequestReply(Address address, uint32_t passkey);
+  void UserPasskeyRequestNegativeReply(Address address);
+  void RemoteOobDataRequestReply(Address address, std::array<uint8_t, 16> c, std::array<uint8_t, 16> r);
+  void RemoteOobDataRequestNegativeReply(Address address);
+  void ReadStoredLinkKey(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag);
+  void WriteStoredLinkKey(std::vector<KeyAndAddress> keys);
+  void DeleteStoredLinkKey(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag);
+  void RefreshEncryptionKey(uint16_t connection_handle);
+  void ReadSimplePairingMode();
+  void WriteSimplePairingMode(Enable simple_pairing_mode);
+  void ReadLocalOobData();
+  void SendKeypressNotification(Address address, KeypressNotificationType notification_type);
+  void ReadLocalOobExtendedData();
+  void ReadEncryptionKeySize(uint16_t connection_handle);
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+
+  void Start() override;
+
+  void Stop() override;
+
+  std::string ToString() const override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+};
+
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/classic_security_manager_test.cc b/gd/hci/classic_security_manager_test.cc
new file mode 100644
index 0000000..b2c936e
--- /dev/null
+++ b/gd/hci/classic_security_manager_test.cc
@@ -0,0 +1,420 @@
+/*
+ * 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 "hci/classic_security_manager.h"
+
+#include <condition_variable>
+#include "gtest/gtest.h"
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using common::OnceCallback;
+using os::Handler;
+using os::Thread;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class CommandQueueEntry {
+ public:
+  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+                    OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler)
+      : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)),
+        caller_handler(handler) {}
+
+  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+                    OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler)
+      : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)),
+        caller_handler(handler) {}
+
+  std::unique_ptr<CommandPacketBuilder> command;
+  bool waiting_for_status_;
+  OnceCallback<void(CommandStatusView)> on_status;
+  OnceCallback<void(CommandCompleteView)> on_complete;
+  Handler* caller_handler;
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status,
+                      Handler* handler) override {
+    auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_status), handler);
+    command_queue_.push(std::move(command_queue_entry));
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      OnceCallback<void(CommandCompleteView)> on_complete, Handler* handler) override {
+    auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_complete), handler);
+    command_queue_.push(std::move(command_queue_entry));
+  }
+
+  std::unique_ptr<CommandQueueEntry> GetLastCommand() {
+    EXPECT_FALSE(command_queue_.empty());
+    auto last = std::move(command_queue_.front());
+    command_queue_.pop();
+    return last;
+  }
+
+  void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+                            Handler* handler) override {
+    registered_events_[event_code] = event_handler;
+  }
+
+  void UnregisterEventHandler(EventCode event_code) override {
+    registered_events_.erase(event_code);
+  }
+
+  void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    EXPECT_TRUE(event.IsValid());
+    EventCode event_code = event.GetEventCode();
+    EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end());
+    registered_events_[event_code].Run(event);
+  }
+
+  void ListDependencies(ModuleList* list) override {}
+  void Start() override {}
+  void Stop() override {}
+
+ private:
+  std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+  std::queue<std::unique_ptr<CommandQueueEntry>> command_queue_;
+};
+
+class ClassicSecurityManagerTest : public ::testing::Test, public ::bluetooth::hci::ClassicSecurityCommandCallbacks {
+ protected:
+  void SetUp() override {
+    test_hci_layer_ = new TestHciLayer;
+    handler_ = new Handler(&thread_);
+    fake_registry_.InjectTestModule(&TestHciLayer::Factory, test_hci_layer_);
+    fake_registry_.Start<ClassicSecurityManager>(&thread_);
+    classic_security_manager_ =
+        static_cast<ClassicSecurityManager*>(fake_registry_.GetModuleUnderTest(&ClassicSecurityManager::Factory));
+    classic_security_manager_->RegisterCallbacks(this, handler_);
+    test_hci_layer_->RegisterEventHandler(
+        EventCode::COMMAND_COMPLETE, base::Bind(&ClassicSecurityManagerTest::ExpectCommand, common::Unretained(this)),
+        nullptr);
+    test_hci_layer_->RegisterEventHandler(
+        EventCode::COMMAND_STATUS,
+        base::Bind(&ClassicSecurityManagerTest::ExpectCommandStatus, common::Unretained(this)), nullptr);
+
+    Address::FromString("A1:A2:A3:A4:A5:A6", remote);
+  }
+
+  void TearDown() override {
+    handler_->Clear();
+    delete handler_;
+    fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20));
+    fake_registry_.StopAll();
+    command_complete_ = false;
+  }
+
+  void ExpectCommand(EventPacketView packet) {
+    CommandCompleteView command_complete_view = CommandCompleteView::Create(std::move(packet));
+    auto last_command_queue_entry = test_hci_layer_->GetLastCommand();
+    auto last_command = std::move(last_command_queue_entry->command);
+    auto command_packet = GetPacketView(std::move(last_command));
+    CommandPacketView command_packet_view = CommandPacketView::Create(command_packet);
+
+    // verify command complete event match last command opcode
+    EXPECT_TRUE(command_packet_view.IsValid());
+    EXPECT_TRUE(command_complete_view.IsValid());
+    EXPECT_EQ(command_packet_view.GetOpCode(), command_complete_view.GetCommandOpCode());
+
+    // verify callback triggered
+    auto caller_handler = last_command_queue_entry->caller_handler;
+    caller_handler->Post(BindOnce(std::move(last_command_queue_entry->on_complete), std::move(command_complete_view)));
+    std::unique_lock<std::mutex> lock(mutex_);
+    EXPECT_FALSE(callback_done.wait_for(lock, std::chrono::seconds(3)) == std::cv_status::timeout);
+
+    command_complete_ = true;
+  }
+
+  void ExpectCommandStatus(EventPacketView packet) {
+    CommandStatusView command_status_view = CommandStatusView::Create(std::move(packet));
+    auto last_command_queue_entry = test_hci_layer_->GetLastCommand();
+    auto last_command = std::move(last_command_queue_entry->command);
+    auto command_packet = GetPacketView(std::move(last_command));
+    CommandPacketView command_packet_view = CommandPacketView::Create(command_packet);
+
+    // verify command complete event match last command opcode
+    EXPECT_TRUE(command_packet_view.IsValid());
+    EXPECT_TRUE(command_status_view.IsValid());
+    EXPECT_EQ(command_packet_view.GetOpCode(), command_status_view.GetCommandOpCode());
+
+    command_complete_ = true;
+  }
+
+  void OnCommandComplete(CommandCompleteView status) override {
+    callback_done.notify_one();
+  }
+
+  TestModuleRegistry fake_registry_;
+  TestHciLayer* test_hci_layer_ = nullptr;
+  os::Thread& thread_ = fake_registry_.GetTestThread();
+  Handler* handler_ = nullptr;
+  ClassicSecurityManager* classic_security_manager_ = nullptr;
+  Address remote;
+  mutable std::mutex mutex_;
+  std::condition_variable callback_done;
+  bool command_complete_ = false;
+};
+
+TEST_F(ClassicSecurityManagerTest, startup_teardown) {}
+
+TEST_F(ClassicSecurityManagerTest, send_link_key_request_reply) {
+  common::LinkKey link_key;
+  common::LinkKey::FromString("4c68384139f574d836bcf34e9dfb01bf\0", link_key);
+  classic_security_manager_->LinkKeyRequestReply(remote, link_key);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::LINK_KEY_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_link_key_request_negative_reply) {
+  classic_security_manager_->LinkKeyRequestNegativeReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_pin_code_request_reply) {
+  classic_security_manager_->PinCodeRequestReply(remote, 6, "123456");
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::PIN_CODE_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_pin_code_request_negative_reply) {
+  classic_security_manager_->PinCodeRequestNegativeReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_io_capability_request_reply) {
+  IoCapability io_capability = (IoCapability)0x00;
+  OobDataPresent oob_present = (OobDataPresent)0x00;
+  AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+  classic_security_manager_->IoCapabilityRequestReply(remote, io_capability, oob_present, authentication_requirements);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::IO_CAPABILITY_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_io_capability_request_negative_reply) {
+  ErrorCode reason = (ErrorCode)0x01;
+  classic_security_manager_->IoCapabilityRequestNegativeReply(remote, reason);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_confirmation_request_reply) {
+  classic_security_manager_->UserConfirmationRequestReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::USER_CONFIRMATION_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_confirmation_request_negative_reply) {
+  classic_security_manager_->UserConfirmationRequestNegativeReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_passkey_request_reply) {
+  classic_security_manager_->UserPasskeyRequestReply(remote, 999999);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::USER_PASSKEY_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_passkey_request_negative_reply) {
+  classic_security_manager_->UserPasskeyRequestNegativeReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_remote_oob_data_request_reply) {
+  std::array<uint8_t, 16> c;
+  std::array<uint8_t, 16> r;
+  for (int i = 0; i < 16; i++) {
+    c[i] = (uint8_t)i;
+    r[i] = (uint8_t)i + 16;
+  }
+  classic_security_manager_->RemoteOobDataRequestReply(remote, c, r);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_remote_oob_data_request_negative_reply) {
+  classic_security_manager_->RemoteOobDataRequestNegativeReply(remote);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_stored_link_key) {
+  ReadStoredLinkKeyReadAllFlag read_all_flag = (ReadStoredLinkKeyReadAllFlag)0x01;
+  classic_security_manager_->ReadStoredLinkKey(remote, read_all_flag);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::READ_STORED_LINK_KEY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_delete_stored_link_key) {
+  DeleteStoredLinkKeyDeleteAllFlag delete_all_flag = (DeleteStoredLinkKeyDeleteAllFlag)0x01;
+  classic_security_manager_->DeleteStoredLinkKey(remote, delete_all_flag);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::DELETE_STORED_LINK_KEY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_refresh_encryption_key) {
+  classic_security_manager_->RefreshEncryptionKey(0x01);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandStatusBuilder::Create(ErrorCode::SUCCESS, 0x01, OpCode::REFRESH_ENCRYPTION_KEY, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_simple_pairing_mode) {
+  classic_security_manager_->ReadSimplePairingMode();
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::READ_SIMPLE_PAIRING_MODE, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_write_simple_pairing_mode) {
+  Enable simple_pairing_mode = (Enable)0x01;
+  classic_security_manager_->WriteSimplePairingMode(simple_pairing_mode);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::WRITE_SIMPLE_PAIRING_MODE, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_local_oob_data) {
+  classic_security_manager_->ReadLocalOobData();
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(0x01, OpCode::READ_LOCAL_OOB_DATA, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_keypress_notification) {
+  KeypressNotificationType notification_type = (KeypressNotificationType)0x01;
+  classic_security_manager_->SendKeypressNotification(remote, notification_type);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::SEND_KEYPRESS_NOTIFICATION, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_local_oob_extended_data) {
+  classic_security_manager_->ReadLocalOobExtendedData();
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::READ_LOCAL_OOB_EXTENDED_DATA, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_encryption_key_size) {
+  classic_security_manager_->ReadEncryptionKeySize(0x01);
+  EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+  auto payload = std::make_unique<RawBuilder>();
+  test_hci_layer_->IncomingEvent(
+      CommandCompleteBuilder::Create(0x01, OpCode::READ_ENCRYPTION_KEY_SIZE, std::move(payload)));
+  EXPECT_TRUE(command_complete_);
+}
+
+}  // namespace
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/controller.cc b/gd/hci/controller.cc
index 2637a99..1bd6150 100644
--- a/gd/hci/controller.cc
+++ b/gd/hci/controller.cc
@@ -43,10 +43,71 @@
     hci_->RegisterEventHandler(EventCode::NUMBER_OF_COMPLETED_PACKETS,
                                Bind(&Controller::impl::NumberOfCompletedPackets, common::Unretained(this)),
                                module_.GetHandler());
+
+    hci_->EnqueueCommand(ReadLocalNameBuilder::Create(),
+                         BindOnce(&Controller::impl::read_local_name_complete_handler, common::Unretained(this)),
+                         module_.GetHandler());
+    hci_->EnqueueCommand(
+        ReadLocalVersionInformationBuilder::Create(),
+        BindOnce(&Controller::impl::read_local_version_information_complete_handler, common::Unretained(this)),
+        module_.GetHandler());
+    hci_->EnqueueCommand(
+        ReadLocalSupportedCommandsBuilder::Create(),
+        BindOnce(&Controller::impl::read_local_supported_commands_complete_handler, common::Unretained(this)),
+        module_.GetHandler());
+    hci_->EnqueueCommand(
+        ReadLocalSupportedFeaturesBuilder::Create(),
+        BindOnce(&Controller::impl::read_local_supported_features_complete_handler, common::Unretained(this)),
+        module_.GetHandler());
+
+    // Wait for all extended features read
+    std::promise<void> features_promise;
+    auto features_future = features_promise.get_future();
+    hci_->EnqueueCommand(ReadLocalExtendedFeaturesBuilder::Create(0x00),
+                         BindOnce(&Controller::impl::read_local_extended_features_complete_handler,
+                                  common::Unretained(this), std::move(features_promise)),
+                         module_.GetHandler());
+    features_future.wait();
+
     hci_->EnqueueCommand(ReadBufferSizeBuilder::Create(),
                          BindOnce(&Controller::impl::read_buffer_size_complete_handler, common::Unretained(this)),
                          module_.GetHandler());
 
+    hci_->EnqueueCommand(LeReadBufferSizeBuilder::Create(),
+                         BindOnce(&Controller::impl::le_read_buffer_size_handler, common::Unretained(this)),
+                         module_.GetHandler());
+
+    hci_->EnqueueCommand(
+        LeReadLocalSupportedFeaturesBuilder::Create(),
+        BindOnce(&Controller::impl::le_read_local_supported_features_handler, common::Unretained(this)),
+        module_.GetHandler());
+
+    hci_->EnqueueCommand(LeReadSupportedStatesBuilder::Create(),
+                         BindOnce(&Controller::impl::le_read_supported_states_handler, common::Unretained(this)),
+                         module_.GetHandler());
+
+    if (is_supported(OpCode::LE_READ_MAXIMUM_DATA_LENGTH)) {
+      hci_->EnqueueCommand(LeReadMaximumDataLengthBuilder::Create(),
+                           BindOnce(&Controller::impl::le_read_maximum_data_length_handler, common::Unretained(this)),
+                           module_.GetHandler());
+    }
+    if (is_supported(OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH)) {
+      hci_->EnqueueCommand(
+          LeReadMaximumAdvertisingDataLengthBuilder::Create(),
+          BindOnce(&Controller::impl::le_read_maximum_advertising_data_length_handler, common::Unretained(this)),
+          module_.GetHandler());
+    }
+    if (is_supported(OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS)) {
+      hci_->EnqueueCommand(
+          LeReadNumberOfSupportedAdvertisingSetsBuilder::Create(),
+          BindOnce(&Controller::impl::le_read_number_of_supported_advertising_sets_handler, common::Unretained(this)),
+          module_.GetHandler());
+    }
+
+    hci_->EnqueueCommand(LeGetVendorCapabilitiesBuilder::Create(),
+                         BindOnce(&Controller::impl::le_get_vendor_capabilities_handler, common::Unretained(this)),
+                         module_.GetHandler());
+
     // We only need to synchronize the last read. Make BD_ADDR to be the last one.
     std::promise<void> promise;
     auto future = promise.get_future();
@@ -66,9 +127,9 @@
     ASSERT(acl_credits_handler_ != nullptr);
     auto complete_view = NumberOfCompletedPacketsView::Create(event);
     ASSERT(complete_view.IsValid());
-    for (auto completed_packets : complete_view.GetHandlesAndCompletedPackets()) {
-      uint16_t handle = completed_packets & 0x0fff;
-      uint16_t credits = (completed_packets & 0xffff0000) >> 16;
+    for (auto completed_packets : complete_view.GetCompletedPackets()) {
+      uint16_t handle = completed_packets.connection_handle_;
+      uint16_t credits = completed_packets.host_num_of_completed_packets_;
       acl_credits_handler_->Post(Bind(acl_credits_callback_, handle, credits));
     }
   }
@@ -80,6 +141,64 @@
     acl_credits_handler_ = handler;
   }
 
+  void read_local_name_complete_handler(CommandCompleteView view) {
+    auto complete_view = ReadLocalNameCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    std::array<uint8_t, 248> local_name_array = complete_view.GetLocalName();
+
+    local_name_ = std::string(local_name_array.begin(), local_name_array.end());
+    // erase \0
+    local_name_.erase(std::find(local_name_.begin(), local_name_.end(), '\0'), local_name_.end());
+  }
+
+  void read_local_version_information_complete_handler(CommandCompleteView view) {
+    auto complete_view = ReadLocalVersionInformationCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+
+    local_version_information_ = complete_view.GetLocalVersionInformation();
+  }
+
+  void read_local_supported_commands_complete_handler(CommandCompleteView view) {
+    auto complete_view = ReadLocalSupportedCommandsCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    local_supported_commands_ = complete_view.GetSupportedCommands();
+  }
+
+  void read_local_supported_features_complete_handler(CommandCompleteView view) {
+    auto complete_view = ReadLocalSupportedFeaturesCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    local_supported_features_ = complete_view.GetLmpFeatures();
+  }
+
+  void read_local_extended_features_complete_handler(std::promise<void> promise, CommandCompleteView view) {
+    auto complete_view = ReadLocalExtendedFeaturesCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    uint8_t page_number = complete_view.GetPageNumber();
+    maximum_page_number_ = complete_view.GetMaximumPageNumber();
+    extended_lmp_features_array_.push_back(complete_view.GetExtendedLmpFeatures());
+
+    // Query all extended features
+    if (page_number < maximum_page_number_) {
+      page_number++;
+      hci_->EnqueueCommand(ReadLocalExtendedFeaturesBuilder::Create(page_number),
+                           BindOnce(&Controller::impl::read_local_extended_features_complete_handler,
+                                    common::Unretained(this), std::move(promise)),
+                           module_.GetHandler());
+    } else {
+      promise.set_value();
+    }
+  }
+
   void read_buffer_size_complete_handler(CommandCompleteView view) {
     auto complete_view = ReadBufferSizeCompleteView::Create(view);
     ASSERT(complete_view.IsValid());
@@ -101,18 +220,471 @@
     promise.set_value();
   }
 
+  void le_read_buffer_size_handler(CommandCompleteView view) {
+    auto complete_view = LeReadBufferSizeCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_buffer_size_ = complete_view.GetLeBufferSize();
+  }
+
+  void le_read_local_supported_features_handler(CommandCompleteView view) {
+    auto complete_view = LeReadLocalSupportedFeaturesCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_local_supported_features_ = complete_view.GetLeFeatures();
+  }
+
+  void le_read_supported_states_handler(CommandCompleteView view) {
+    auto complete_view = LeReadSupportedStatesCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_supported_states_ = complete_view.GetLeStates();
+  }
+
+  void le_read_maximum_data_length_handler(CommandCompleteView view) {
+    auto complete_view = LeReadMaximumDataLengthCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_maximum_data_length_ = complete_view.GetLeMaximumDataLength();
+  }
+
+  void le_read_maximum_advertising_data_length_handler(CommandCompleteView view) {
+    auto complete_view = LeReadMaximumAdvertisingDataLengthCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_maximum_advertising_data_length_ = complete_view.GetMaximumAdvertisingDataLength();
+  }
+
+  void le_read_number_of_supported_advertising_sets_handler(CommandCompleteView view) {
+    auto complete_view = LeReadNumberOfSupportedAdvertisingSetsCompleteView::Create(view);
+    ASSERT(complete_view.IsValid());
+    ErrorCode status = complete_view.GetStatus();
+    ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+    le_number_supported_advertising_sets_ = complete_view.GetNumberSupportedAdvertisingSets();
+  }
+
+  void le_get_vendor_capabilities_handler(CommandCompleteView view) {
+    auto complete_view = LeGetVendorCapabilitiesCompleteView::Create(view);
+
+    vendor_capabilities_.is_supported_ = 0x00;
+    vendor_capabilities_.max_advt_instances_ = 0x00;
+    vendor_capabilities_.offloaded_resolution_of_private_address_ = 0x00;
+    vendor_capabilities_.total_scan_results_storage_ = 0x00;
+    vendor_capabilities_.max_irk_list_sz_ = 0x00;
+    vendor_capabilities_.filtering_support_ = 0x00;
+    vendor_capabilities_.max_filter_ = 0x00;
+    vendor_capabilities_.activity_energy_info_support_ = 0x00;
+    vendor_capabilities_.version_supported_ = 0x00;
+    vendor_capabilities_.version_supported_ = 0x00;
+    vendor_capabilities_.total_num_of_advt_tracked_ = 0x00;
+    vendor_capabilities_.extended_scan_support_ = 0x00;
+    vendor_capabilities_.debug_logging_supported_ = 0x00;
+    vendor_capabilities_.le_address_generation_offloading_support_ = 0x00;
+    vendor_capabilities_.a2dp_source_offload_capability_mask_ = 0x00;
+    vendor_capabilities_.bluetooth_quality_report_support_ = 0x00;
+
+    if (complete_view.IsValid()) {
+      vendor_capabilities_.is_supported_ = 0x01;
+
+      // v0.55
+      BaseVendorCapabilities base_vendor_capabilities = complete_view.GetBaseVendorCapabilities();
+      vendor_capabilities_.max_advt_instances_ = base_vendor_capabilities.max_advt_instances_;
+      vendor_capabilities_.offloaded_resolution_of_private_address_ =
+          base_vendor_capabilities.offloaded_resolution_of_private_address_;
+      vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_;
+      vendor_capabilities_.max_irk_list_sz_ = base_vendor_capabilities.max_irk_list_sz_;
+      vendor_capabilities_.filtering_support_ = base_vendor_capabilities.filtering_support_;
+      vendor_capabilities_.max_filter_ = base_vendor_capabilities.max_filter_;
+      vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_;
+      if (complete_view.GetPayload().size() == 0) {
+        vendor_capabilities_.version_supported_ = 55;
+        return;
+      }
+
+      // v0.95
+      auto v95 = LeGetVendorCapabilitiesComplete095View::Create(complete_view);
+      if (!v95.IsValid()) {
+        LOG_ERROR("invalid data for hci requirements v0.95");
+        return;
+      }
+      vendor_capabilities_.version_supported_ = v95.GetVersionSupported();
+      vendor_capabilities_.total_num_of_advt_tracked_ = v95.GetTotalNumOfAdvtTracked();
+      vendor_capabilities_.extended_scan_support_ = v95.GetExtendedScanSupport();
+      vendor_capabilities_.debug_logging_supported_ = v95.GetDebugLoggingSupported();
+      if (vendor_capabilities_.version_supported_ <= 95 || complete_view.GetPayload().size() == 0) {
+        return;
+      }
+
+      // v0.96
+      auto v96 = LeGetVendorCapabilitiesComplete096View::Create(v95);
+      if (!v96.IsValid()) {
+        LOG_ERROR("invalid data for hci requirements v0.96");
+        return;
+      }
+      vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport();
+      if (vendor_capabilities_.version_supported_ <= 96 || complete_view.GetPayload().size() == 0) {
+        return;
+      }
+
+      // v0.98
+      auto v98 = LeGetVendorCapabilitiesComplete098View::Create(v96);
+      if (!v98.IsValid()) {
+        LOG_ERROR("invalid data for hci requirements v0.98");
+        return;
+      }
+      vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask();
+      vendor_capabilities_.bluetooth_quality_report_support_ = v98.GetBluetoothQualityReportSupport();
+    }
+  }
+
+  void set_event_mask(uint64_t event_mask) {
+    std::unique_ptr<SetEventMaskBuilder> packet = SetEventMaskBuilder::Create(event_mask);
+    hci_->EnqueueCommand(std::move(packet),
+                         BindOnce(&Controller::impl::check_status<SetEventMaskCompleteView>, common::Unretained(this)),
+                         module_.GetHandler());
+  }
+
+  void reset() {
+    std::unique_ptr<ResetBuilder> packet = ResetBuilder::Create();
+    hci_->EnqueueCommand(std::move(packet),
+                         BindOnce(&Controller::impl::check_status<ResetCompleteView>, common::Unretained(this)),
+                         module_.GetHandler());
+  }
+
+  void set_event_filter(std::unique_ptr<SetEventFilterBuilder> packet) {
+    hci_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&Controller::impl::check_status<SetEventFilterCompleteView>, common::Unretained(this)),
+        module_.GetHandler());
+  }
+
+  void write_local_name(std::string local_name) {
+    ASSERT(local_name.length() <= 248);
+    // Fill remaining char with 0
+    local_name.append(std::string(248 - local_name.length(), '\0'));
+    std::array<uint8_t, 248> local_name_array;
+    std::copy(std::begin(local_name), std::end(local_name), std::begin(local_name_array));
+
+    std::unique_ptr<WriteLocalNameBuilder> packet = WriteLocalNameBuilder::Create(local_name_array);
+    hci_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&Controller::impl::check_status<WriteLocalNameCompleteView>, common::Unretained(this)),
+        module_.GetHandler());
+  }
+
+  void host_buffer_size(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+                        uint16_t host_total_num_acl_data_packets, uint16_t host_total_num_synchronous_data_packets) {
+    std::unique_ptr<HostBufferSizeBuilder> packet =
+        HostBufferSizeBuilder::Create(host_acl_data_packet_length, host_synchronous_data_packet_length,
+                                      host_total_num_acl_data_packets, host_total_num_synchronous_data_packets);
+    hci_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&Controller::impl::check_status<HostBufferSizeCompleteView>, common::Unretained(this)),
+        module_.GetHandler());
+  }
+
+  void le_set_event_mask(uint64_t le_event_mask) {
+    std::unique_ptr<LeSetEventMaskBuilder> packet = LeSetEventMaskBuilder::Create(le_event_mask);
+    hci_->EnqueueCommand(
+        std::move(packet),
+        BindOnce(&Controller::impl::check_status<LeSetEventMaskCompleteView>, common::Unretained(this)),
+        module_.GetHandler());
+  }
+
+  template <class T>
+  void check_status(CommandCompleteView view) {
+    ASSERT(view.IsValid());
+    auto status_view = T::Create(view);
+    ASSERT(status_view.IsValid());
+    ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+  }
+
+#define OP_CODE_MAPPING(name)                                                  \
+  case OpCode::name: {                                                         \
+    uint16_t index = (uint16_t)OpCodeIndex::name;                              \
+    uint16_t byte_index = index / 10;                                          \
+    uint16_t bit_index = index % 10;                                           \
+    bool supported = local_supported_commands_[byte_index] & (1 << bit_index); \
+    if (!supported) {                                                          \
+      LOG_WARN("unsupported command opcode: 0x%04x", (uint16_t)OpCode::name);  \
+    }                                                                          \
+    return supported;                                                          \
+  }
+
+  bool is_supported(OpCode op_code) {
+    switch (op_code) {
+      OP_CODE_MAPPING(INQUIRY)
+      OP_CODE_MAPPING(INQUIRY_CANCEL)
+      OP_CODE_MAPPING(PERIODIC_INQUIRY_MODE)
+      OP_CODE_MAPPING(EXIT_PERIODIC_INQUIRY_MODE)
+      OP_CODE_MAPPING(CREATE_CONNECTION)
+      OP_CODE_MAPPING(DISCONNECT)
+      OP_CODE_MAPPING(CREATE_CONNECTION_CANCEL)
+      OP_CODE_MAPPING(ACCEPT_CONNECTION_REQUEST)
+      OP_CODE_MAPPING(REJECT_CONNECTION_REQUEST)
+      OP_CODE_MAPPING(LINK_KEY_REQUEST_REPLY)
+      OP_CODE_MAPPING(LINK_KEY_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(PIN_CODE_REQUEST_REPLY)
+      OP_CODE_MAPPING(PIN_CODE_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(CHANGE_CONNECTION_PACKET_TYPE)
+      OP_CODE_MAPPING(AUTHENTICATION_REQUESTED)
+      OP_CODE_MAPPING(SET_CONNECTION_ENCRYPTION)
+      OP_CODE_MAPPING(CHANGE_CONNECTION_LINK_KEY)
+      OP_CODE_MAPPING(MASTER_LINK_KEY)
+      OP_CODE_MAPPING(REMOTE_NAME_REQUEST)
+      OP_CODE_MAPPING(REMOTE_NAME_REQUEST_CANCEL)
+      OP_CODE_MAPPING(READ_REMOTE_SUPPORTED_FEATURES)
+      OP_CODE_MAPPING(READ_REMOTE_EXTENDED_FEATURES)
+      OP_CODE_MAPPING(READ_REMOTE_VERSION_INFORMATION)
+      OP_CODE_MAPPING(READ_CLOCK_OFFSET)
+      OP_CODE_MAPPING(READ_LMP_HANDLE)
+      OP_CODE_MAPPING(HOLD_MODE)
+      OP_CODE_MAPPING(SNIFF_MODE)
+      OP_CODE_MAPPING(EXIT_SNIFF_MODE)
+      OP_CODE_MAPPING(QOS_SETUP)
+      OP_CODE_MAPPING(ROLE_DISCOVERY)
+      OP_CODE_MAPPING(SWITCH_ROLE)
+      OP_CODE_MAPPING(READ_LINK_POLICY_SETTINGS)
+      OP_CODE_MAPPING(WRITE_LINK_POLICY_SETTINGS)
+      OP_CODE_MAPPING(READ_DEFAULT_LINK_POLICY_SETTINGS)
+      OP_CODE_MAPPING(WRITE_DEFAULT_LINK_POLICY_SETTINGS)
+      OP_CODE_MAPPING(FLOW_SPECIFICATION)
+      OP_CODE_MAPPING(SET_EVENT_MASK)
+      OP_CODE_MAPPING(RESET)
+      OP_CODE_MAPPING(SET_EVENT_FILTER)
+      OP_CODE_MAPPING(FLUSH)
+      OP_CODE_MAPPING(READ_PIN_TYPE)
+      OP_CODE_MAPPING(WRITE_PIN_TYPE)
+      OP_CODE_MAPPING(READ_STORED_LINK_KEY)
+      OP_CODE_MAPPING(WRITE_STORED_LINK_KEY)
+      OP_CODE_MAPPING(DELETE_STORED_LINK_KEY)
+      OP_CODE_MAPPING(WRITE_LOCAL_NAME)
+      OP_CODE_MAPPING(READ_LOCAL_NAME)
+      OP_CODE_MAPPING(READ_CONNECTION_ACCEPT_TIMEOUT)
+      OP_CODE_MAPPING(WRITE_CONNECTION_ACCEPT_TIMEOUT)
+      OP_CODE_MAPPING(READ_PAGE_TIMEOUT)
+      OP_CODE_MAPPING(WRITE_PAGE_TIMEOUT)
+      OP_CODE_MAPPING(READ_SCAN_ENABLE)
+      OP_CODE_MAPPING(WRITE_SCAN_ENABLE)
+      OP_CODE_MAPPING(READ_PAGE_SCAN_ACTIVITY)
+      OP_CODE_MAPPING(WRITE_PAGE_SCAN_ACTIVITY)
+      OP_CODE_MAPPING(READ_INQUIRY_SCAN_ACTIVITY)
+      OP_CODE_MAPPING(WRITE_INQUIRY_SCAN_ACTIVITY)
+      OP_CODE_MAPPING(READ_AUTHENTICATION_ENABLE)
+      OP_CODE_MAPPING(WRITE_AUTHENTICATION_ENABLE)
+      OP_CODE_MAPPING(READ_CLASS_OF_DEVICE)
+      OP_CODE_MAPPING(WRITE_CLASS_OF_DEVICE)
+      OP_CODE_MAPPING(READ_VOICE_SETTING)
+      OP_CODE_MAPPING(WRITE_VOICE_SETTING)
+      OP_CODE_MAPPING(READ_AUTOMATIC_FLUSH_TIMEOUT)
+      OP_CODE_MAPPING(WRITE_AUTOMATIC_FLUSH_TIMEOUT)
+      OP_CODE_MAPPING(READ_NUM_BROADCAST_RETRANSMITS)
+      OP_CODE_MAPPING(WRITE_NUM_BROADCAST_RETRANSMITS)
+      OP_CODE_MAPPING(READ_HOLD_MODE_ACTIVITY)
+      OP_CODE_MAPPING(WRITE_HOLD_MODE_ACTIVITY)
+      OP_CODE_MAPPING(READ_TRANSMIT_POWER_LEVEL)
+      OP_CODE_MAPPING(READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE)
+      OP_CODE_MAPPING(WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE)
+      OP_CODE_MAPPING(SET_CONTROLLER_TO_HOST_FLOW_CONTROL)
+      OP_CODE_MAPPING(HOST_BUFFER_SIZE)
+      OP_CODE_MAPPING(HOST_NUM_COMPLETED_PACKETS)
+      OP_CODE_MAPPING(READ_LINK_SUPERVISION_TIMEOUT)
+      OP_CODE_MAPPING(WRITE_LINK_SUPERVISION_TIMEOUT)
+      OP_CODE_MAPPING(READ_NUMBER_OF_SUPPORTED_IAC)
+      OP_CODE_MAPPING(READ_CURRENT_IAC_LAP)
+      OP_CODE_MAPPING(WRITE_CURRENT_IAC_LAP)
+      OP_CODE_MAPPING(SET_AFH_HOST_CHANNEL_CLASSIFICATION)
+      OP_CODE_MAPPING(READ_INQUIRY_SCAN_TYPE)
+      OP_CODE_MAPPING(WRITE_INQUIRY_SCAN_TYPE)
+      OP_CODE_MAPPING(READ_INQUIRY_MODE)
+      OP_CODE_MAPPING(WRITE_INQUIRY_MODE)
+      OP_CODE_MAPPING(READ_PAGE_SCAN_TYPE)
+      OP_CODE_MAPPING(WRITE_PAGE_SCAN_TYPE)
+      OP_CODE_MAPPING(READ_AFH_CHANNEL_ASSESSMENT_MODE)
+      OP_CODE_MAPPING(WRITE_AFH_CHANNEL_ASSESSMENT_MODE)
+      OP_CODE_MAPPING(READ_LOCAL_VERSION_INFORMATION)
+      OP_CODE_MAPPING(READ_LOCAL_SUPPORTED_FEATURES)
+      OP_CODE_MAPPING(READ_LOCAL_EXTENDED_FEATURES)
+      OP_CODE_MAPPING(READ_BUFFER_SIZE)
+      OP_CODE_MAPPING(READ_BD_ADDR)
+      OP_CODE_MAPPING(READ_FAILED_CONTACT_COUNTER)
+      OP_CODE_MAPPING(RESET_FAILED_CONTACT_COUNTER)
+      OP_CODE_MAPPING(READ_LINK_QUALITY)
+      OP_CODE_MAPPING(READ_RSSI)
+      OP_CODE_MAPPING(READ_AFH_CHANNEL_MAP)
+      OP_CODE_MAPPING(READ_CLOCK)
+      OP_CODE_MAPPING(READ_LOOPBACK_MODE)
+      OP_CODE_MAPPING(WRITE_LOOPBACK_MODE)
+      OP_CODE_MAPPING(ENABLE_DEVICE_UNDER_TEST_MODE)
+      OP_CODE_MAPPING(SETUP_SYNCHRONOUS_CONNECTION)
+      OP_CODE_MAPPING(ACCEPT_SYNCHRONOUS_CONNECTION)
+      OP_CODE_MAPPING(REJECT_SYNCHRONOUS_CONNECTION)
+      OP_CODE_MAPPING(READ_EXTENDED_INQUIRY_RESPONSE)
+      OP_CODE_MAPPING(WRITE_EXTENDED_INQUIRY_RESPONSE)
+      OP_CODE_MAPPING(REFRESH_ENCRYPTION_KEY)
+      OP_CODE_MAPPING(SNIFF_SUBRATING)
+      OP_CODE_MAPPING(READ_SIMPLE_PAIRING_MODE)
+      OP_CODE_MAPPING(WRITE_SIMPLE_PAIRING_MODE)
+      OP_CODE_MAPPING(READ_LOCAL_OOB_DATA)
+      OP_CODE_MAPPING(READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL)
+      OP_CODE_MAPPING(WRITE_INQUIRY_TRANSMIT_POWER_LEVEL)
+      OP_CODE_MAPPING(IO_CAPABILITY_REQUEST_REPLY)
+      OP_CODE_MAPPING(USER_CONFIRMATION_REQUEST_REPLY)
+      OP_CODE_MAPPING(USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(USER_PASSKEY_REQUEST_REPLY)
+      OP_CODE_MAPPING(USER_PASSKEY_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(REMOTE_OOB_DATA_REQUEST_REPLY)
+      OP_CODE_MAPPING(WRITE_SIMPLE_PAIRING_DEBUG_MODE)
+      OP_CODE_MAPPING(REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(SEND_KEYPRESS_NOTIFICATION)
+      OP_CODE_MAPPING(IO_CAPABILITY_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(READ_ENCRYPTION_KEY_SIZE)
+      OP_CODE_MAPPING(READ_DATA_BLOCK_SIZE)
+      OP_CODE_MAPPING(READ_LE_HOST_SUPPORT)
+      OP_CODE_MAPPING(WRITE_LE_HOST_SUPPORT)
+      OP_CODE_MAPPING(LE_SET_EVENT_MASK)
+      OP_CODE_MAPPING(LE_READ_BUFFER_SIZE)
+      OP_CODE_MAPPING(LE_READ_LOCAL_SUPPORTED_FEATURES)
+      OP_CODE_MAPPING(LE_SET_RANDOM_ADDRESS)
+      OP_CODE_MAPPING(LE_SET_ADVERTISING_PARAMETERS)
+      OP_CODE_MAPPING(LE_READ_ADVERTISING_CHANNEL_TX_POWER)
+      OP_CODE_MAPPING(LE_SET_ADVERTISING_DATA)
+      OP_CODE_MAPPING(LE_SET_SCAN_RESPONSE_DATA)
+      OP_CODE_MAPPING(LE_SET_ADVERTISING_ENABLE)
+      OP_CODE_MAPPING(LE_SET_SCAN_PARAMETERS)
+      OP_CODE_MAPPING(LE_SET_SCAN_ENABLE)
+      OP_CODE_MAPPING(LE_CREATE_CONNECTION)
+      OP_CODE_MAPPING(LE_CREATE_CONNECTION_CANCEL)
+      OP_CODE_MAPPING(LE_READ_WHITE_LIST_SIZE)
+      OP_CODE_MAPPING(LE_CLEAR_WHITE_LIST)
+      OP_CODE_MAPPING(LE_ADD_DEVICE_TO_WHITE_LIST)
+      OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_WHITE_LIST)
+      OP_CODE_MAPPING(LE_CONNECTION_UPDATE)
+      OP_CODE_MAPPING(LE_SET_HOST_CHANNEL_CLASSIFICATION)
+      OP_CODE_MAPPING(LE_READ_CHANNEL_MAP)
+      OP_CODE_MAPPING(LE_READ_REMOTE_FEATURES)
+      OP_CODE_MAPPING(LE_ENCRYPT)
+      OP_CODE_MAPPING(LE_RAND)
+      OP_CODE_MAPPING(LE_START_ENCRYPTION)
+      OP_CODE_MAPPING(LE_LONG_TERM_KEY_REQUEST_REPLY)
+      OP_CODE_MAPPING(LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(LE_READ_SUPPORTED_STATES)
+      OP_CODE_MAPPING(LE_RECEIVER_TEST)
+      OP_CODE_MAPPING(LE_TRANSMITTER_TEST)
+      OP_CODE_MAPPING(LE_TEST_END)
+      OP_CODE_MAPPING(ENHANCED_SETUP_SYNCHRONOUS_CONNECTION)
+      OP_CODE_MAPPING(ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION)
+      OP_CODE_MAPPING(READ_LOCAL_SUPPORTED_CODECS)
+      OP_CODE_MAPPING(READ_SECURE_CONNECTIONS_HOST_SUPPORT)
+      OP_CODE_MAPPING(WRITE_SECURE_CONNECTIONS_HOST_SUPPORT)
+      OP_CODE_MAPPING(READ_LOCAL_OOB_EXTENDED_DATA)
+      OP_CODE_MAPPING(WRITE_SECURE_CONNECTIONS_TEST_MODE)
+      OP_CODE_MAPPING(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY)
+      OP_CODE_MAPPING(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY)
+      OP_CODE_MAPPING(LE_SET_DATA_LENGTH)
+      OP_CODE_MAPPING(LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH)
+      OP_CODE_MAPPING(LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH)
+      OP_CODE_MAPPING(LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND)
+      OP_CODE_MAPPING(LE_GENERATE_DHKEY_COMMAND)
+      OP_CODE_MAPPING(LE_ADD_DEVICE_TO_RESOLVING_LIST)
+      OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_RESOLVING_LIST)
+      OP_CODE_MAPPING(LE_CLEAR_RESOLVING_LIST)
+      OP_CODE_MAPPING(LE_READ_RESOLVING_LIST_SIZE)
+      OP_CODE_MAPPING(LE_READ_PEER_RESOLVABLE_ADDRESS)
+      OP_CODE_MAPPING(LE_READ_LOCAL_RESOLVABLE_ADDRESS)
+      OP_CODE_MAPPING(LE_SET_ADDRESS_RESOLUTION_ENABLE)
+      OP_CODE_MAPPING(LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT)
+      OP_CODE_MAPPING(LE_READ_MAXIMUM_DATA_LENGTH)
+      OP_CODE_MAPPING(LE_READ_PHY)
+      OP_CODE_MAPPING(LE_SET_DEFAULT_PHY)
+      OP_CODE_MAPPING(LE_SET_PHY)
+      OP_CODE_MAPPING(LE_ENHANCED_RECEIVER_TEST)
+      OP_CODE_MAPPING(LE_ENHANCED_TRANSMITTER_TEST)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_PARAMETERS)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_DATA)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_ENABLE)
+      OP_CODE_MAPPING(LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH)
+      OP_CODE_MAPPING(LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS)
+      OP_CODE_MAPPING(LE_REMOVE_ADVERTISING_SET)
+      OP_CODE_MAPPING(LE_CLEAR_ADVERTISING_SETS)
+      OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_PARAM)
+      OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_DATA)
+      OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_ENABLE)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_SCAN_PARAMETERS)
+      OP_CODE_MAPPING(LE_SET_EXTENDED_SCAN_ENABLE)
+      OP_CODE_MAPPING(LE_EXTENDED_CREATE_CONNECTION)
+      OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_CREATE_SYNC)
+      OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL)
+      OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_TERMINATE_SYNC)
+      OP_CODE_MAPPING(LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST)
+      OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST)
+      OP_CODE_MAPPING(LE_CLEAR_PERIODIC_ADVERTISING_LIST)
+      OP_CODE_MAPPING(LE_READ_PERIODIC_ADVERTISING_LIST_SIZE)
+      OP_CODE_MAPPING(LE_READ_TRANSMIT_POWER)
+      OP_CODE_MAPPING(LE_READ_RF_PATH_COMPENSATION_POWER)
+      OP_CODE_MAPPING(LE_WRITE_RF_PATH_COMPENSATION_POWER)
+      OP_CODE_MAPPING(LE_SET_PRIVACY_MODE)
+      // vendor specific
+      case OpCode::LE_GET_VENDOR_CAPABILITIES:
+        return vendor_capabilities_.is_supported_ == 0x01;
+      case OpCode::LE_MULTI_ADVT:
+        return vendor_capabilities_.max_advt_instances_ != 0x00;
+      case OpCode::LE_BATCH_SCAN:
+        return vendor_capabilities_.total_scan_results_storage_ != 0x00;
+      case OpCode::LE_ADV_FILTER:
+        return vendor_capabilities_.filtering_support_ == 0x01;
+      case OpCode::LE_TRACK_ADV:
+        return vendor_capabilities_.total_num_of_advt_tracked_ > 0;
+      case OpCode::LE_ENERGY_INFO:
+        return vendor_capabilities_.activity_energy_info_support_ == 0x01;
+      case OpCode::LE_EXTENDED_SCAN_PARAMS:
+        return vendor_capabilities_.extended_scan_support_ == 0x01;
+      case OpCode::CONTROLLER_DEBUG_INFO:
+        return vendor_capabilities_.debug_logging_supported_ == 0x01;
+      case OpCode::CONTROLLER_A2DP_OPCODE:
+        return vendor_capabilities_.a2dp_source_offload_capability_mask_ != 0x00;
+      // undefined in local_supported_commands_
+      case OpCode::CREATE_NEW_UNIT_KEY:
+      case OpCode::READ_LOCAL_SUPPORTED_COMMANDS:
+        return true;
+      case OpCode::NONE:
+        return false;
+    }
+    return false;
+  }
+#undef OP_CODE_MAPPING
+
   Controller& module_;
 
   HciLayer* hci_;
 
   Callback<void(uint16_t, uint16_t)> acl_credits_callback_;
   Handler* acl_credits_handler_ = nullptr;
-
+  LocalVersionInformation local_version_information_;
+  std::array<uint8_t, 64> local_supported_commands_;
+  uint64_t local_supported_features_;
+  uint8_t maximum_page_number_;
+  std::vector<uint64_t> extended_lmp_features_array_;
   uint16_t acl_buffer_length_ = 0;
   uint16_t acl_buffers_ = 0;
   uint8_t sco_buffer_length_ = 0;
   uint16_t sco_buffers_ = 0;
-  common::Address mac_address_;
+  Address mac_address_;
+  std::string local_name_;
+  LeBufferSize le_buffer_size_;
+  uint64_t le_local_supported_features_;
+  uint64_t le_supported_states_;
+  LeMaximumDataLength le_maximum_data_length_;
+  uint16_t le_maximum_advertising_data_length_;
+  uint16_t le_number_supported_advertising_sets_;
+  VendorCapabilities vendor_capabilities_;
 };  // namespace hci
 
 Controller::Controller() : impl_(std::make_unique<impl>(*this)) {}
@@ -124,26 +696,155 @@
   impl_->RegisterCompletedAclPacketsCallback(cb, handler);  // TODO hsz: why here?
 }
 
-uint16_t Controller::GetControllerAclPacketLength() {
+std::string Controller::GetControllerLocalName() const {
+  return impl_->local_name_;
+}
+
+LocalVersionInformation Controller::GetControllerLocalVersionInformation() const {
+  return impl_->local_version_information_;
+}
+
+std::array<uint8_t, 64> Controller::GetControllerLocalSupportedCommands() const {
+  return impl_->local_supported_commands_;
+}
+
+uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() const {
+  return impl_->maximum_page_number_;
+}
+
+uint64_t Controller::GetControllerLocalSupportedFeatures() const {
+  return impl_->local_supported_features_;
+}
+
+uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) const {
+  if (page_number <= impl_->maximum_page_number_) {
+    return impl_->extended_lmp_features_array_[page_number];
+  }
+  return 0x00;
+}
+
+uint16_t Controller::GetControllerAclPacketLength() const {
   return impl_->acl_buffer_length_;
 }
 
-uint16_t Controller::GetControllerNumAclPacketBuffers() {
+uint16_t Controller::GetControllerNumAclPacketBuffers() const {
   return impl_->acl_buffers_;
 }
 
-uint8_t Controller::GetControllerScoPacketLength() {
+uint8_t Controller::GetControllerScoPacketLength() const {
   return impl_->sco_buffer_length_;
 }
 
-uint16_t Controller::GetControllerNumScoPacketBuffers() {
+uint16_t Controller::GetControllerNumScoPacketBuffers() const {
   return impl_->sco_buffers_;
 }
 
-common::Address Controller::GetControllerMacAddress() {
+Address Controller::GetControllerMacAddress() const {
   return impl_->mac_address_;
 }
 
+void Controller::SetEventMask(uint64_t event_mask) {
+  GetHandler()->Post(common::BindOnce(&impl::set_event_mask, common::Unretained(impl_.get()), event_mask));
+}
+
+void Controller::Reset() {
+  GetHandler()->Post(common::BindOnce(&impl::reset, common::Unretained(impl_.get())));
+}
+
+void Controller::SetEventFilterClearAll() {
+  std::unique_ptr<SetEventFilterClearAllBuilder> packet = SetEventFilterClearAllBuilder::Create();
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultAllDevices() {
+  std::unique_ptr<SetEventFilterInquiryResultAllDevicesBuilder> packet =
+      SetEventFilterInquiryResultAllDevicesBuilder::Create();
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultClassOfDevice(ClassOfDevice class_of_device,
+                                                          ClassOfDevice class_of_device_mask) {
+  std::unique_ptr<SetEventFilterInquiryResultClassOfDeviceBuilder> packet =
+      SetEventFilterInquiryResultClassOfDeviceBuilder::Create(class_of_device, class_of_device_mask);
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultAddress(Address address) {
+  std::unique_ptr<SetEventFilterInquiryResultAddressBuilder> packet =
+      SetEventFilterInquiryResultAddressBuilder::Create(address);
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag auto_accept_flag) {
+  std::unique_ptr<SetEventFilterConnectionSetupAllDevicesBuilder> packet =
+      SetEventFilterConnectionSetupAllDevicesBuilder::Create(auto_accept_flag);
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupClassOfDevice(ClassOfDevice class_of_device,
+                                                            ClassOfDevice class_of_device_mask,
+                                                            AutoAcceptFlag auto_accept_flag) {
+  std::unique_ptr<SetEventFilterConnectionSetupClassOfDeviceBuilder> packet =
+      SetEventFilterConnectionSetupClassOfDeviceBuilder::Create(class_of_device, class_of_device_mask,
+                                                                auto_accept_flag);
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupAddress(Address address, AutoAcceptFlag auto_accept_flag) {
+  std::unique_ptr<SetEventFilterConnectionSetupAddressBuilder> packet =
+      SetEventFilterConnectionSetupAddressBuilder::Create(address, auto_accept_flag);
+  GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::WriteLocalName(std::string local_name) {
+  impl_->local_name_ = local_name;
+  GetHandler()->Post(common::BindOnce(&impl::write_local_name, common::Unretained(impl_.get()), local_name));
+}
+
+void Controller::HostBufferSize(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+                                uint16_t host_total_num_acl_data_packets,
+                                uint16_t host_total_num_synchronous_data_packets) {
+  GetHandler()->Post(common::BindOnce(&impl::host_buffer_size, common::Unretained(impl_.get()),
+                                      host_acl_data_packet_length, host_synchronous_data_packet_length,
+                                      host_total_num_acl_data_packets, host_total_num_synchronous_data_packets));
+}
+
+void Controller::LeSetEventMask(uint64_t le_event_mask) {
+  GetHandler()->Post(common::BindOnce(&impl::le_set_event_mask, common::Unretained(impl_.get()), le_event_mask));
+}
+
+LeBufferSize Controller::GetControllerLeBufferSize() const {
+  return impl_->le_buffer_size_;
+}
+
+uint64_t Controller::GetControllerLeLocalSupportedFeatures() const {
+  return impl_->le_local_supported_features_;
+}
+
+uint64_t Controller::GetControllerLeSupportedStates() const {
+  return impl_->le_supported_states_;
+}
+
+LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() const {
+  return impl_->le_maximum_data_length_;
+}
+
+uint16_t Controller::GetControllerLeMaximumAdvertisingDataLength() const {
+  return impl_->le_maximum_advertising_data_length_;
+}
+
+uint16_t Controller::GetControllerLeNumberOfSupportedAdverisingSets() const {
+  return impl_->le_number_supported_advertising_sets_;
+}
+
+VendorCapabilities Controller::GetControllerVendorCapabilities() const {
+  return impl_->vendor_capabilities_;
+}
+
+bool Controller::IsSupported(bluetooth::hci::OpCode op_code) const {
+  return impl_->is_supported(op_code);
+}
+
 const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); });
 
 void Controller::ListDependencies(ModuleList* list) {
@@ -157,5 +858,9 @@
 void Controller::Stop() {
   impl_->Stop();
 }
+
+std::string Controller::ToString() const {
+  return "Controller";
+}
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/hci/controller.h b/gd/hci/controller.h
index b3e70f2..251a5ab 100644
--- a/gd/hci/controller.h
+++ b/gd/hci/controller.h
@@ -16,8 +16,8 @@
 
 #pragma once
 
-#include "common/address.h"
 #include "common/callback.h"
+#include "hci/address.h"
 #include "hci/hci_packets.h"
 #include "module.h"
 #include "os/handler.h"
@@ -34,15 +34,73 @@
   virtual void RegisterCompletedAclPacketsCallback(
       common::Callback<void(uint16_t /* handle */, uint16_t /* num_packets */)> cb, os::Handler* handler);
 
-  virtual uint16_t GetControllerAclPacketLength();
+  virtual std::string GetControllerLocalName() const;
 
-  virtual uint16_t GetControllerNumAclPacketBuffers();
+  virtual LocalVersionInformation GetControllerLocalVersionInformation() const;
 
-  virtual uint8_t GetControllerScoPacketLength();
+  virtual std::array<uint8_t, 64> GetControllerLocalSupportedCommands() const;
 
-  virtual uint16_t GetControllerNumScoPacketBuffers();
+  virtual uint64_t GetControllerLocalSupportedFeatures() const;
 
-  virtual common::Address GetControllerMacAddress();
+  virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const;
+
+  virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const;
+
+  virtual uint16_t GetControllerAclPacketLength() const;
+
+  virtual uint16_t GetControllerNumAclPacketBuffers() const;
+
+  virtual uint8_t GetControllerScoPacketLength() const;
+
+  virtual uint16_t GetControllerNumScoPacketBuffers() const;
+
+  virtual Address GetControllerMacAddress() const;
+
+  virtual void SetEventMask(uint64_t event_mask);
+
+  virtual void Reset();
+
+  virtual void SetEventFilterClearAll();
+
+  virtual void SetEventFilterInquiryResultAllDevices();
+
+  virtual void SetEventFilterInquiryResultClassOfDevice(ClassOfDevice class_of_device,
+                                                        ClassOfDevice class_of_device_mask);
+
+  virtual void SetEventFilterInquiryResultAddress(Address address);
+
+  virtual void SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag auto_accept_flag);
+
+  virtual void SetEventFilterConnectionSetupClassOfDevice(ClassOfDevice class_of_device,
+                                                          ClassOfDevice class_of_device_mask,
+                                                          AutoAcceptFlag auto_accept_flag);
+
+  virtual void SetEventFilterConnectionSetupAddress(Address address, AutoAcceptFlag auto_accept_flag);
+
+  virtual void WriteLocalName(std::string local_name);
+
+  virtual void HostBufferSize(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+                              uint16_t host_total_num_acl_data_packets,
+                              uint16_t host_total_num_synchronous_data_packets);
+
+  // LE controller commands
+  virtual void LeSetEventMask(uint64_t le_event_mask);
+
+  virtual LeBufferSize GetControllerLeBufferSize() const;
+
+  virtual uint64_t GetControllerLeLocalSupportedFeatures() const;
+
+  virtual uint64_t GetControllerLeSupportedStates() const;
+
+  virtual LeMaximumDataLength GetControllerLeMaximumDataLength() const;
+
+  virtual uint16_t GetControllerLeMaximumAdvertisingDataLength() const;
+
+  virtual uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const;
+
+  virtual VendorCapabilities GetControllerVendorCapabilities() const;
+
+  virtual bool IsSupported(OpCode op_code) const;
 
   static const ModuleFactory Factory;
 
@@ -53,6 +111,8 @@
 
   void Stop() override;
 
+  std::string ToString() const override;
+
  private:
   struct impl;
   std::unique_ptr<impl> impl_;
diff --git a/gd/hci/controller_test.cc b/gd/hci/controller_test.cc
index 377a011..9d109f8 100644
--- a/gd/hci/controller_test.cc
+++ b/gd/hci/controller_test.cc
@@ -23,9 +23,9 @@
 
 #include <gtest/gtest.h>
 
-#include "common/address.h"
 #include "common/bind.h"
 #include "common/callback.h"
+#include "hci/address.h"
 #include "hci/hci_layer.h"
 #include "os/thread.h"
 #include "packet/raw_builder.h"
@@ -34,7 +34,6 @@
 namespace hci {
 namespace {
 
-using common::Address;
 using common::BidiQueue;
 using common::BidiQueueEnd;
 using packet::kLittleEndian;
@@ -45,6 +44,7 @@
 constexpr uint16_t kCredits1 = 0x78;
 constexpr uint16_t kHandle2 = 0x456;
 constexpr uint16_t kCredits2 = 0x9a;
+uint16_t feature_spec_version = 55;
 
 PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
   auto bytes = std::make_shared<std::vector<uint8_t>>();
@@ -76,14 +76,111 @@
     uint8_t num_packets = 1;
     std::unique_ptr<packet::BasePacketBuilder> event_builder;
     switch (command.GetOpCode()) {
+      case (OpCode::READ_LOCAL_NAME): {
+        std::array<uint8_t, 248> local_name = {'D', 'U', 'T', '\0'};
+        event_builder = ReadLocalNameCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, local_name);
+      } break;
+      case (OpCode::READ_LOCAL_VERSION_INFORMATION): {
+        LocalVersionInformation local_version_information;
+        local_version_information.hci_version_ = HciVersion::V_5_0;
+        local_version_information.hci_revision_ = 0x1234;
+        local_version_information.lmp_version_ = LmpVersion::V_4_2;
+        local_version_information.manufacturer_name_ = 0xBAD;
+        local_version_information.lmp_subversion_ = 0x5678;
+        event_builder = ReadLocalVersionInformationCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
+                                                                           local_version_information);
+      } break;
+      case (OpCode::READ_LOCAL_SUPPORTED_COMMANDS): {
+        std::array<uint8_t, 64> supported_commands;
+        for (int i = 0; i < 37; i++) {
+          supported_commands[i] = 0xff;
+        }
+        for (int i = 37; i < 64; i++) {
+          supported_commands[i] = 0x00;
+        }
+        event_builder =
+            ReadLocalSupportedCommandsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, supported_commands);
+      } break;
+      case (OpCode::READ_LOCAL_SUPPORTED_FEATURES): {
+        uint64_t lmp_features = 0x012345678abcdef;
+        event_builder =
+            ReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, lmp_features);
+      } break;
+      case (OpCode::READ_LOCAL_EXTENDED_FEATURES): {
+        ReadLocalExtendedFeaturesView read_command = ReadLocalExtendedFeaturesView::Create(command);
+        ASSERT(read_command.IsValid());
+        uint8_t page_bumber = read_command.GetPageNumber();
+        uint64_t lmp_features = 0x012345678abcdef;
+        lmp_features += page_bumber;
+        event_builder = ReadLocalExtendedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, page_bumber,
+                                                                         0x02, lmp_features);
+      } break;
       case (OpCode::READ_BUFFER_SIZE): {
         event_builder = ReadBufferSizeCompleteBuilder::Create(
             num_packets, ErrorCode::SUCCESS, acl_data_packet_length, synchronous_data_packet_length,
             total_num_acl_data_packets, total_num_synchronous_data_packets);
       } break;
       case (OpCode::READ_BD_ADDR): {
-        event_builder = ReadBdAddrCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, common::Address::kAny);
+        event_builder = ReadBdAddrCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, Address::kAny);
       } break;
+      case (OpCode::LE_READ_BUFFER_SIZE): {
+        LeBufferSize le_buffer_size;
+        le_buffer_size.le_data_packet_length_ = 0x16;
+        le_buffer_size.total_num_le_packets_ = 0x08;
+        event_builder = LeReadBufferSizeCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_buffer_size);
+      } break;
+      case (OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES): {
+        event_builder =
+            LeReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abc);
+      } break;
+      case (OpCode::LE_READ_SUPPORTED_STATES): {
+        event_builder =
+            LeReadSupportedStatesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abe);
+      } break;
+      case (OpCode::LE_READ_MAXIMUM_DATA_LENGTH): {
+        LeMaximumDataLength le_maximum_data_length;
+        le_maximum_data_length.supported_max_tx_octets_ = 0x12;
+        le_maximum_data_length.supported_max_tx_time_ = 0x34;
+        le_maximum_data_length.supported_max_rx_octets_ = 0x56;
+        le_maximum_data_length.supported_max_rx_time_ = 0x78;
+        event_builder =
+            LeReadMaximumDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_maximum_data_length);
+      } break;
+      case (OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH): {
+        event_builder =
+            LeReadMaximumAdvertisingDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x0672);
+      } break;
+      case (OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS): {
+        event_builder =
+            LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0xF0);
+      } break;
+      case (OpCode::LE_GET_VENDOR_CAPABILITIES): {
+        BaseVendorCapabilities base_vendor_capabilities;
+        base_vendor_capabilities.max_advt_instances_ = 0x10;
+        base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01;
+        base_vendor_capabilities.total_scan_results_storage_ = 0x2800;
+        base_vendor_capabilities.max_irk_list_sz_ = 0x20;
+        base_vendor_capabilities.filtering_support_ = 0x01;
+        base_vendor_capabilities.max_filter_ = 0x10;
+        base_vendor_capabilities.activity_energy_info_support_ = 0x01;
+
+        auto payload = std::make_unique<RawBuilder>();
+        if (feature_spec_version > 55) {
+          std::vector<uint8_t> payload_bytes = {0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00};
+          payload->AddOctets2(feature_spec_version);
+          payload->AddOctets(payload_bytes);
+        }
+        event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
+                                                                       base_vendor_capabilities, std::move(payload));
+      } break;
+      case (OpCode::SET_EVENT_MASK):
+      case (OpCode::RESET):
+      case (OpCode::SET_EVENT_FILTER):
+      case (OpCode::HOST_BUFFER_SIZE):
+      case (OpCode::LE_SET_EVENT_MASK):
+        command_queue_.push(command);
+        not_empty_.notify_all();
+        return;
       default:
         LOG_INFO("Dropping unhandled packet");
         return;
@@ -110,16 +207,38 @@
   }
 
   void IncomingCredit() {
-    std::vector<uint32_t> handles_and_completed_packets;
-    handles_and_completed_packets.push_back(kCredits1 << 16 | kHandle1);
-    handles_and_completed_packets.push_back(kCredits2 << 16 | kHandle2);
-    auto event_builder = NumberOfCompletedPacketsBuilder::Create(handles_and_completed_packets);
+    std::vector<CompletedPackets> completed_packets;
+    CompletedPackets cp;
+    cp.host_num_of_completed_packets_ = kCredits1;
+    cp.connection_handle_ = kHandle1;
+    completed_packets.push_back(cp);
+    cp.host_num_of_completed_packets_ = kCredits2;
+    cp.connection_handle_ = kHandle2;
+    completed_packets.push_back(cp);
+    auto event_builder = NumberOfCompletedPacketsBuilder::Create(completed_packets);
     auto packet = GetPacketView(std::move(event_builder));
     EventPacketView event = EventPacketView::Create(packet);
     ASSERT(event.IsValid());
     client_handler_->Post(common::BindOnce(number_of_completed_packets_callback_, event));
   }
 
+  CommandPacketView GetCommand(OpCode op_code) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    std::chrono::milliseconds time = std::chrono::milliseconds(3000);
+
+    // wait for command
+    while (command_queue_.size() == 0) {
+      if (not_empty_.wait_for(lock, time) == std::cv_status::timeout) {
+        break;
+      }
+    }
+    ASSERT(command_queue_.size() > 0);
+    CommandPacketView command = command_queue_.front();
+    EXPECT_EQ(command.GetOpCode(), op_code);
+    command_queue_.pop();
+    return command;
+  }
+
   void ListDependencies(ModuleList* list) override {}
   void Start() override {}
   void Stop() override {}
@@ -132,6 +251,9 @@
  private:
   common::Callback<void(EventPacketView)> number_of_completed_packets_callback_;
   os::Handler* client_handler_;
+  std::queue<CommandPacketView> command_queue_;
+  mutable std::mutex mutex_;
+  std::condition_variable not_empty_;
 };
 
 class ControllerTest : public ::testing::Test {
@@ -163,7 +285,147 @@
   ASSERT_EQ(controller_->GetControllerNumAclPacketBuffers(), test_hci_layer_->total_num_acl_data_packets);
   ASSERT_EQ(controller_->GetControllerScoPacketLength(), test_hci_layer_->synchronous_data_packet_length);
   ASSERT_EQ(controller_->GetControllerNumScoPacketBuffers(), test_hci_layer_->total_num_synchronous_data_packets);
-  ASSERT_EQ(controller_->GetControllerMacAddress(), common::Address::kAny);
+  ASSERT_EQ(controller_->GetControllerMacAddress(), Address::kAny);
+  LocalVersionInformation local_version_information = controller_->GetControllerLocalVersionInformation();
+  ASSERT_EQ(local_version_information.hci_version_, HciVersion::V_5_0);
+  ASSERT_EQ(local_version_information.hci_revision_, 0x1234);
+  ASSERT_EQ(local_version_information.lmp_version_, LmpVersion::V_4_2);
+  ASSERT_EQ(local_version_information.manufacturer_name_, 0xBAD);
+  ASSERT_EQ(local_version_information.lmp_subversion_, 0x5678);
+  std::array<uint8_t, 64> supported_commands;
+  for (int i = 0; i < 37; i++) {
+    supported_commands[i] = 0xff;
+  }
+  for (int i = 37; i < 64; i++) {
+    supported_commands[i] = 0x00;
+  }
+  ASSERT_EQ(controller_->GetControllerLocalSupportedCommands(), supported_commands);
+  ASSERT_EQ(controller_->GetControllerLocalSupportedFeatures(), 0x012345678abcdef);
+  ASSERT_EQ(controller_->GetControllerLocalExtendedFeaturesMaxPageNumber(), 0x02);
+  ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(0), 0x012345678abcdef);
+  ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(1), 0x012345678abcdf0);
+  ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(2), 0x012345678abcdf1);
+  ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(100), 0x00);
+  ASSERT_EQ(controller_->GetControllerLeBufferSize().le_data_packet_length_, 0x16);
+  ASSERT_EQ(controller_->GetControllerLeBufferSize().total_num_le_packets_, 0x08);
+  ASSERT_EQ(controller_->GetControllerLeLocalSupportedFeatures(), 0x001f123456789abc);
+  ASSERT_EQ(controller_->GetControllerLeSupportedStates(), 0x001f123456789abe);
+  ASSERT_EQ(controller_->GetControllerLeMaximumDataLength().supported_max_tx_octets_, 0x12);
+  ASSERT_EQ(controller_->GetControllerLeMaximumDataLength().supported_max_rx_octets_, 0x56);
+  ASSERT_EQ(controller_->GetControllerLeMaximumAdvertisingDataLength(), 0x0672);
+  ASSERT_EQ(controller_->GetControllerLeNumberOfSupportedAdverisingSets(), 0xF0);
+}
+
+TEST_F(ControllerTest, read_write_local_name) {
+  ASSERT_EQ(controller_->GetControllerLocalName(), "DUT");
+  controller_->WriteLocalName("New name");
+  ASSERT_EQ(controller_->GetControllerLocalName(), "New name");
+}
+
+TEST_F(ControllerTest, send_set_event_mask_command) {
+  controller_->SetEventMask(0x00001FFFFFFFFFFF);
+  auto packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_MASK);
+  auto command = SetEventMaskView::Create(packet);
+  ASSERT(command.IsValid());
+  ASSERT_EQ(command.GetEventMask(), 0x00001FFFFFFFFFFF);
+}
+
+TEST_F(ControllerTest, send_reset_command) {
+  controller_->Reset();
+  auto packet = test_hci_layer_->GetCommand(OpCode::RESET);
+  auto command = ResetView::Create(packet);
+  ASSERT(command.IsValid());
+}
+
+TEST_F(ControllerTest, send_set_event_filter_command) {
+  controller_->SetEventFilterInquiryResultAllDevices();
+  auto packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+  auto set_event_filter_view1 = SetEventFilterView::Create(packet);
+  auto set_event_filter_inquiry_result_view1 = SetEventFilterInquiryResultView::Create(set_event_filter_view1);
+  auto command1 = SetEventFilterInquiryResultAllDevicesView::Create(set_event_filter_inquiry_result_view1);
+  ASSERT(command1.IsValid());
+
+  ClassOfDevice class_of_device({0xab, 0xcd, 0xef});
+  ClassOfDevice class_of_device_mask({0x12, 0x34, 0x56});
+  controller_->SetEventFilterInquiryResultClassOfDevice(class_of_device, class_of_device_mask);
+  packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+  auto set_event_filter_view2 = SetEventFilterView::Create(packet);
+  auto set_event_filter_inquiry_result_view2 = SetEventFilterInquiryResultView::Create(set_event_filter_view2);
+  auto command2 = SetEventFilterInquiryResultClassOfDeviceView::Create(set_event_filter_inquiry_result_view2);
+  ASSERT(command2.IsValid());
+  ASSERT_EQ(command2.GetClassOfDevice(), class_of_device);
+
+  Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+  controller_->SetEventFilterConnectionSetupAddress(bdaddr, AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED);
+  packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+  auto set_event_filter_view3 = SetEventFilterView::Create(packet);
+  auto set_event_filter_connection_setup_view = SetEventFilterConnectionSetupView::Create(set_event_filter_view3);
+  auto command3 = SetEventFilterConnectionSetupAddressView::Create(set_event_filter_connection_setup_view);
+  ASSERT(command3.IsValid());
+  ASSERT_EQ(command3.GetAddress(), bdaddr);
+}
+
+TEST_F(ControllerTest, send_host_buffer_size_command) {
+  controller_->HostBufferSize(0xFF00, 0xF1, 0xFF02, 0xFF03);
+  auto packet = test_hci_layer_->GetCommand(OpCode::HOST_BUFFER_SIZE);
+  auto command = HostBufferSizeView::Create(packet);
+  ASSERT(command.IsValid());
+  ASSERT_EQ(command.GetHostAclDataPacketLength(), 0xFF00);
+  ASSERT_EQ(command.GetHostSynchronousDataPacketLength(), 0xF1);
+  ASSERT_EQ(command.GetHostTotalNumAclDataPackets(), 0xFF02);
+  ASSERT_EQ(command.GetHostTotalNumSynchronousDataPackets(), 0xFF03);
+}
+
+TEST_F(ControllerTest, send_le_set_event_mask_command) {
+  controller_->LeSetEventMask(0x000000000000001F);
+  auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_EVENT_MASK);
+  auto command = LeSetEventMaskView::Create(packet);
+  ASSERT(command.IsValid());
+  ASSERT_EQ(command.GetLeEventMask(), 0x000000000000001F);
+}
+
+TEST_F(ControllerTest, is_supported_test) {
+  ASSERT_TRUE(controller_->IsSupported(OpCode::INQUIRY));
+  ASSERT_TRUE(controller_->IsSupported(OpCode::REJECT_CONNECTION_REQUEST));
+  ASSERT_TRUE(controller_->IsSupported(OpCode::ACCEPT_CONNECTION_REQUEST));
+  ASSERT_FALSE(controller_->IsSupported(OpCode::LE_REMOVE_ADVERTISING_SET));
+  ASSERT_FALSE(controller_->IsSupported(OpCode::LE_CLEAR_ADVERTISING_SETS));
+  ASSERT_FALSE(controller_->IsSupported(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM));
+}
+
+TEST_F(ControllerTest, feature_spec_version_055_test) {
+  EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 55);
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+  feature_spec_version = 95;
+}
+
+TEST_F(ControllerTest, feature_spec_version_095_test) {
+  EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 95);
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+  feature_spec_version = 96;
+}
+
+TEST_F(ControllerTest, feature_spec_version_096_test) {
+  EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 96);
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+  feature_spec_version = 98;
+}
+
+TEST_F(ControllerTest, feature_spec_version_098_test) {
+  EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 98);
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+  EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+  EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+  EXPECT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
 }
 
 std::promise<void> credits1_set;
diff --git a/gd/hci/device.cc b/gd/hci/device.cc
new file mode 100644
index 0000000..d008dae
--- /dev/null
+++ b/gd/hci/device.cc
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ *  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 "hci/device.h"
+
+using namespace bluetooth::hci;
+
+std::string Device::generate_uid() {
+  // TODO(optedoblivion): Figure out a good way to do this for what we want
+  // to do
+  // TODO(optedoblivion): Need to make a way to override something for LE pub addr case
+  // Not sure if something like this is needed, but here is the idea (I think it came from mylesgw)
+  // CLASSIC: have all 0s in front for classic then have private address
+  // LE: have first public address in front then all 0s
+  // LE: have first public address in front then private address
+  //
+  return address_.ToString();
+}
diff --git a/gd/hci/device.h b/gd/hci/device.h
new file mode 100644
index 0000000..8324d00
--- /dev/null
+++ b/gd/hci/device.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ *  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 "hci/address.h"
+#include "hci/class_of_device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * Used to determine device functionality
+ */
+enum DeviceType { DUAL, CLASSIC, LE };
+
+/**
+ * Represents a physical HCI device.
+ *
+ * <p>Contains all of the metadata required to represent a phycial device.
+ *
+ * <p>Devices should only be created and modified by HCI.
+ */
+class Device {
+ public:
+  virtual ~Device() = default;
+
+  Address GetAddress() const {
+    return address_;
+  }
+
+  /**
+   * Returns 1 of 3 enum values for device's type (DUAL, CLASSIC, LE)
+   */
+  DeviceType GetDeviceType() const {
+    return device_type_;
+  }
+
+  /**
+   * Unique identifier for bluetooth devices
+   *
+   * @return string representation of the uuid
+   */
+  std::string /** use UUID when ported */ GetUuid() {
+    return uid_;
+  }
+
+  std::string GetName() {
+    return name_;
+  }
+
+  ClassOfDevice GetClassOfDevice() {
+    return class_of_device_;
+  }
+
+  bool IsBonded() {
+    return is_bonded_;
+  }
+
+  bool operator==(const Device& rhs) const {
+    return this->uid_ == rhs.uid_ && this->address_ == rhs.address_ && this->device_type_ == rhs.device_type_ &&
+           this->is_bonded_ == rhs.is_bonded_;
+  }
+
+ protected:
+  friend class DeviceDatabase;
+  friend class DualDevice;
+
+  /**
+   * @param raw_address the address of the device
+   * @param device_type specify the type of device to create
+   */
+  Device(Address address, DeviceType device_type)
+      : address_(address), device_type_(device_type), uid_(generate_uid()), name_(""), class_of_device_() {}
+
+  /**
+   * Called only by friend class DeviceDatabase
+   *
+   * @param address
+   */
+  virtual void SetAddress(Address address) {
+    address_ = address;
+    uid_ = generate_uid();
+  }
+
+  /**
+   * Set the type of the device.
+   *
+   * <p>Needed by dual mode to arbitrarily set the valure to DUAL for corresponding LE/Classic devices
+   *
+   * @param type of device
+   */
+  void SetDeviceType(DeviceType type) {
+    device_type_ = type;
+  }
+
+  void SetName(std::string& name) {
+    name_ = name;
+  }
+
+  void SetClassOfDevice(ClassOfDevice class_of_device) {
+    class_of_device_ = class_of_device;
+  }
+
+  void SetIsBonded(bool is_bonded) {
+    is_bonded_ = is_bonded;
+  }
+
+ private:
+  Address address_{Address::kEmpty};
+  DeviceType device_type_;
+  std::string uid_;
+  std::string name_;
+  ClassOfDevice class_of_device_;
+  bool is_bonded_ = false;
+
+  /* Uses specific information about the device to calculate a UID */
+  std::string generate_uid();
+};
+
+}  // namespace bluetooth::hci
diff --git a/gd/hci/device_database.cc b/gd/hci/device_database.cc
new file mode 100644
index 0000000..0027074
--- /dev/null
+++ b/gd/hci/device_database.cc
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ *  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 "hci/device_database.h"
+
+#include <memory>
+#include <utility>
+
+#include "hci/classic_device.h"
+#include "hci/dual_device.h"
+#include "hci/le_device.h"
+#include "os/log.h"
+
+using namespace bluetooth::hci;
+
+std::shared_ptr<ClassicDevice> DeviceDatabase::CreateClassicDevice(Address address) {
+  ClassicDevice device(address);
+  const std::string uuid = device.GetUuid();
+  AddDeviceToMap(std::move(device));
+  return GetClassicDevice(uuid);
+}
+
+std::shared_ptr<LeDevice> DeviceDatabase::CreateLeDevice(Address address) {
+  LeDevice device(address);
+  const std::string uuid = device.GetUuid();
+  AddDeviceToMap(std::move(device));
+  return GetLeDevice(uuid);
+}
+
+std::shared_ptr<DualDevice> DeviceDatabase::CreateDualDevice(Address address) {
+  auto classic = CreateClassicDevice(address);
+  auto le = CreateLeDevice(address);
+  if (classic && le) {
+    DualDevice device(address, classic, le);
+    std::string uuid = device.GetUuid();
+    AddDeviceToMap(std::move(device));
+    return GetDualDevice(uuid);
+  }
+  LOG_WARN("Attempting to instert a DUAL device that already exists!");
+  return std::shared_ptr<DualDevice>();
+}
+
+bool DeviceDatabase::RemoveDevice(const std::shared_ptr<Device>& device) {
+  const DeviceType type = device->GetDeviceType();
+  bool success;
+  switch (type) {
+    case CLASSIC:
+      success = false;
+      {
+        std::lock_guard<std::mutex> lock(device_map_mutex_);
+        auto classic_it = classic_device_map_.find(device->GetUuid());
+        // If we have a record with the same key
+        if (classic_it != classic_device_map_.end()) {
+          classic_device_map_.erase(device->GetUuid());
+          success = true;
+        }
+      }
+      if (success) {
+        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+      } else {
+        LOG_WARN("Device not in database!");
+      }
+      return success;
+    case LE:
+      success = false;
+      {
+        std::lock_guard<std::mutex> lock(device_map_mutex_);
+        auto le_it = le_device_map_.find(device->GetUuid());
+        // If we have a record with the same key
+        if (le_it != le_device_map_.end()) {
+          le_device_map_.erase(device->GetUuid());
+          success = true;
+        }
+      }
+      if (success) {
+        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+      } else {
+        LOG_WARN("Device not in database!");
+      }
+      return success;
+    case DUAL:
+      std::shared_ptr<DualDevice> dual_device = nullptr;
+      {
+        std::lock_guard<std::mutex> lock(device_map_mutex_);
+        auto dual_it = dual_device_map_.find(device->GetUuid());
+        if (dual_it != dual_device_map_.end()) {
+          dual_device = GetDualDevice(device->GetUuid());
+        }
+      }
+      success = false;
+      if (dual_device != nullptr) {
+        if (RemoveDevice(dual_device->GetClassicDevice()) && RemoveDevice(dual_device->GetLeDevice())) {
+          dual_device_map_.erase(device->GetUuid());
+          success = true;
+        }
+      }
+      if (success) {
+        ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+      } else {
+        LOG_WARN("Device not in database!");
+      }
+      return success;
+  }
+}
+
+std::shared_ptr<ClassicDevice> DeviceDatabase::GetClassicDevice(const std::string& uuid) {
+  std::lock_guard<std::mutex> lock(device_map_mutex_);
+  auto it = classic_device_map_.find(uuid);
+  if (it != classic_device_map_.end()) {
+    return it->second;
+  }
+  LOG_WARN("Device '%s' not found!", uuid.c_str());
+  return std::shared_ptr<ClassicDevice>();
+}
+
+std::shared_ptr<LeDevice> DeviceDatabase::GetLeDevice(const std::string& uuid) {
+  std::lock_guard<std::mutex> lock(device_map_mutex_);
+  auto it = le_device_map_.find(uuid);
+  if (it != le_device_map_.end()) {
+    return it->second;
+  }
+  LOG_WARN("Device '%s' not found!", uuid.c_str());
+  return std::shared_ptr<LeDevice>();
+}
+
+std::shared_ptr<DualDevice> DeviceDatabase::GetDualDevice(const std::string& uuid) {
+  std::lock_guard<std::mutex> lock(device_map_mutex_);
+  auto it = dual_device_map_.find(uuid);
+  if (it != dual_device_map_.end()) {
+    return it->second;
+  }
+  LOG_WARN("Device '%s' not found!", uuid.c_str());
+  return std::shared_ptr<DualDevice>();
+}
+
+bool DeviceDatabase::UpdateDeviceAddress(const std::shared_ptr<Device>& device, Address new_address) {
+  // Hold onto device
+  const DeviceType type = device->GetDeviceType();
+  if (type == CLASSIC) {
+    auto classic_device = GetClassicDevice(device->GetUuid());
+    // This gets rid of the shared_ptr in the map
+    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+    classic_device->SetAddress(new_address);
+    // Move the value located at the pointer
+    return AddDeviceToMap(std::move(*(classic_device.get())));
+  } else if (type == LE) {
+    auto le_device = GetLeDevice(device->GetUuid());
+    // This gets rid of the shared_ptr in the map
+    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+    le_device->SetAddress(new_address);
+    // Move the value located at the pointer
+    return AddDeviceToMap(std::move(*(le_device.get())));
+  } else if (type == DUAL) {
+    auto dual_device = GetDualDevice(device->GetUuid());
+    // This gets rid of the shared_ptr in the map
+    ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+    dual_device->SetAddress(new_address);
+    // Move the value located at the pointer
+    return AddDeviceToMap(std::move(*(dual_device.get())));
+  }
+  LOG_ALWAYS_FATAL("Someone added a device type but didn't account for it here.");
+  return false;
+}
+
+bool DeviceDatabase::AddDeviceToMap(ClassicDevice&& device) {
+  const std::string uuid = device.GetUuid();
+  bool success = false;
+  {
+    std::lock_guard<std::mutex> lock(device_map_mutex_);
+    auto it = classic_device_map_.find(device.GetUuid());
+    // If we have a record with the same key
+    if (it != classic_device_map_.end()) {
+      // We don't want to insert and overwrite
+      return false;
+    }
+    std::shared_ptr<ClassicDevice> device_ptr = std::make_shared<ClassicDevice>(std::move(device));
+    // returning the boolean value of insert success
+    if (classic_device_map_
+            .insert(std::pair<std::string, std::shared_ptr<ClassicDevice>>(device_ptr->GetUuid(), device_ptr))
+            .second) {
+      success = true;
+    }
+  }
+  if (success) {
+    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+  } else {
+    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+  }
+  return success;
+}
+
+bool DeviceDatabase::AddDeviceToMap(LeDevice&& device) {
+  const std::string uuid = device.GetUuid();
+  bool success = false;
+  {
+    std::lock_guard<std::mutex> lock(device_map_mutex_);
+    auto it = le_device_map_.find(device.GetUuid());
+    // If we have a record with the same key
+    if (it != le_device_map_.end()) {
+      // We don't want to insert and overwrite
+      return false;
+    }
+    std::shared_ptr<LeDevice> device_ptr = std::make_shared<LeDevice>(std::move(device));
+    // returning the boolean value of insert success
+    if (le_device_map_.insert(std::pair<std::string, std::shared_ptr<LeDevice>>(device_ptr->GetUuid(), device_ptr))
+            .second) {
+      success = true;
+    }
+  }
+  if (success) {
+    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+  } else {
+    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+  }
+  return success;
+}
+
+bool DeviceDatabase::AddDeviceToMap(DualDevice&& device) {
+  const std::string uuid = device.GetUuid();
+  bool success = false;
+  {
+    std::lock_guard<std::mutex> lock(device_map_mutex_);
+    auto it = dual_device_map_.find(device.GetUuid());
+    // If we have a record with the same key
+    if (it != dual_device_map_.end()) {
+      // We don't want to insert and overwrite
+      return false;
+    }
+    std::shared_ptr<DualDevice> device_ptr = std::make_shared<DualDevice>(std::move(device));
+    // returning the boolean value of insert success
+    if (dual_device_map_.insert(std::pair<std::string, std::shared_ptr<DualDevice>>(device_ptr->GetUuid(), device_ptr))
+            .second) {
+      success = true;
+    }
+  }
+  if (success) {
+    ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+  } else {
+    LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+  }
+  return success;
+}
+
+bool DeviceDatabase::WriteToDisk() {
+  // TODO(optedoblivion): Implement
+  // TODO(optedoblivion): FIX ME!
+  // If synchronous stack dies before async write, we can miss adding device
+  // post(WriteToDisk());
+  // Current Solution: Synchronous disk I/O...
+  std::lock_guard<std::mutex> lock(device_map_mutex_);
+  // Collect information to sync to database
+  // Create SQL query for insert/update
+  // submit SQL
+  return true;
+}
+
+bool DeviceDatabase::ReadFromDisk() {
+  // TODO(optedoblivion): Implement
+  // Current Solution: Synchronous disk I/O...
+  std::lock_guard<std::mutex> lock(device_map_mutex_);
+  return true;
+}
diff --git a/gd/hci/device_database.h b/gd/hci/device_database.h
new file mode 100644
index 0000000..88434a4
--- /dev/null
+++ b/gd/hci/device_database.h
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ *  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 <map>
+#include <mutex>
+
+#include "hci/classic_device.h"
+#include "hci/device.h"
+#include "hci/dual_device.h"
+#include "hci/le_device.h"
+#include "os/log.h"
+
+namespace bluetooth::hci {
+
+/**
+ * Stores all of the paired or connected devices in the database.
+ *
+ * <p>If a device is stored here it is actively being used by the stack.
+ *
+ * <p>This database is not meant for scan results.
+ */
+class DeviceDatabase {
+ public:
+  DeviceDatabase() : classic_device_map_(), le_device_map_(), dual_device_map_() {
+    if (!ReadFromDisk()) {
+      LOG_WARN("First boot or missing data!");
+    }
+  }
+
+  /**
+   * Adds a device to the internal memory map and triggers a WriteToDisk.
+   *
+   * @param address private address for device
+   * @return weak pointer to the device or empty pointer if device already exists
+   */
+  std::shared_ptr<ClassicDevice> CreateClassicDevice(Address address);
+
+  /**
+   * Adds a device to the internal memory map and triggers a WriteToDisk.
+   *
+   * @param address private address for device
+   * @return weak pointer to the device or empty pointer if device already exists
+   */
+  std::shared_ptr<LeDevice> CreateLeDevice(Address address);
+
+  /**
+   * Adds a device to the internal memory map and triggers a WriteToDisk.
+   *
+   * @param address private address for device
+   * @return weak pointer to the device or empty pointer if device already exists
+   */
+  std::shared_ptr<DualDevice> CreateDualDevice(Address address);
+
+  /**
+   * Fetches a Classic Device matching the given uuid.
+   *
+   * @param uuid generated uuid from a Device
+   * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+   */
+  std::shared_ptr<ClassicDevice> GetClassicDevice(const std::string& uuid);
+
+  /**
+   * Fetches a Le Device matching the given uuid.
+   *
+   * @param uuid generated uuid from a Device
+   * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+   */
+  std::shared_ptr<LeDevice> GetLeDevice(const std::string& uuid);
+
+  /**
+   * Fetches a Dual Device matching the given uuid.
+   *
+   * @param uuid generated uuid from a Device
+   * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+   */
+  std::shared_ptr<DualDevice> GetDualDevice(const std::string& uuid);
+
+  /**
+   * Removes a device from the internal database.
+   *
+   * @param device weak pointer to device to remove from the database
+   * @return <code>true</code> if the device is removed
+   */
+  bool RemoveDevice(const std::shared_ptr<Device>& device);
+
+  /**
+   * Changes an address for a device.
+   *
+   * Also fixes the key mapping for the device.
+   *
+   * @param new_address this will replace the existing address
+   * @return <code>true</code> if updated
+   */
+  bool UpdateDeviceAddress(const std::shared_ptr<Device>& device, Address new_address);
+
+  // TODO(optedoblivion): Make interfaces for device modification
+  // We want to keep the device modification encapsulated to the DeviceDatabase.
+  // Pass around shared_ptr to device, device metadata only accessible via Getters.
+  // Choices:
+  //  a) Have Getters/Setters on device object
+  //  b) Have Getters/Setters on device database accepting a device object
+  //  c) Have Getters on device object and Setters on device database accepting a device object
+  // I chose to go with option c for now as I think it is the best option.
+
+  /**
+   * Fetches a list of classic devices.
+   *
+   * @return vector of weak pointers to classic devices
+   */
+  std::vector<std::shared_ptr<Device>> GetClassicDevices();
+
+  /**
+   * Fetches a list of le devices
+   *
+   * @return vector of weak pointers to le devices
+   */
+  std::vector<std::shared_ptr<Device>> GetLeDevices();
+
+ private:
+  std::mutex device_map_mutex_;
+  std::map<std::string, std::shared_ptr<ClassicDevice>> classic_device_map_;
+  std::map<std::string, std::shared_ptr<LeDevice>> le_device_map_;
+  std::map<std::string, std::shared_ptr<DualDevice>> dual_device_map_;
+
+  bool AddDeviceToMap(ClassicDevice&& device);
+  bool AddDeviceToMap(LeDevice&& device);
+  bool AddDeviceToMap(DualDevice&& device);
+
+  bool WriteToDisk();
+  bool ReadFromDisk();
+};
+
+}  // namespace bluetooth::hci
diff --git a/gd/hci/device_database_test.cc b/gd/hci/device_database_test.cc
new file mode 100644
index 0000000..330571d
--- /dev/null
+++ b/gd/hci/device_database_test.cc
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ *  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 "device_database.h"
+#include "classic_device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+namespace bluetooth::hci {
+namespace {
+
+Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+std::string address_str = "06:05:04:03:02:01";
+class DeviceDatabaseTest : public ::testing::Test {
+ protected:
+  DeviceDatabaseTest() = default;
+
+  void SetUp() override {}
+
+  void TearDown() override {}
+
+  DeviceDatabase device_database_;
+};
+
+TEST_F(DeviceDatabaseTest, create_classic_device) {
+  auto classic_device = device_database_.CreateClassicDevice(address);
+  ASSERT_TRUE(classic_device);
+  ASSERT_EQ(CLASSIC, classic_device->GetDeviceType());
+  ASSERT_EQ(address_str, classic_device->GetUuid());
+}
+
+TEST_F(DeviceDatabaseTest, create_le_device) {
+  auto le_device = device_database_.CreateLeDevice(address);
+  ASSERT_TRUE(le_device);
+  ASSERT_EQ(LE, le_device->GetDeviceType());
+  ASSERT_EQ(address_str, le_device->GetUuid());
+}
+
+TEST_F(DeviceDatabaseTest, create_dual_device) {
+  auto dual_device = device_database_.CreateDualDevice(address);
+  ASSERT_TRUE(dual_device);
+  ASSERT_EQ(DUAL, dual_device->GetDeviceType());
+  ASSERT_EQ(DUAL, dual_device->GetClassicDevice()->GetDeviceType());
+  ASSERT_EQ(DUAL, dual_device->GetLeDevice()->GetDeviceType());
+  ASSERT_EQ(address_str, dual_device->GetUuid());
+}
+
+// Shouldn't fail when creating twice.  Should just get back a s_ptr the same device
+TEST_F(DeviceDatabaseTest, create_classic_device_twice) {
+  auto classic_device = device_database_.CreateClassicDevice(address);
+  ASSERT_TRUE(classic_device);
+  ASSERT_EQ(CLASSIC, classic_device->GetDeviceType());
+  ASSERT_EQ(address_str, classic_device->GetUuid());
+  ASSERT_TRUE(device_database_.CreateClassicDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, create_le_device_twice) {
+  auto le_device = device_database_.CreateLeDevice(address);
+  ASSERT_TRUE(le_device);
+  ASSERT_EQ(LE, le_device->GetDeviceType());
+  ASSERT_EQ(address_str, le_device->GetUuid());
+  ASSERT_TRUE(device_database_.CreateLeDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, create_dual_device_twice) {
+  auto dual_device = device_database_.CreateDualDevice(address);
+  ASSERT_TRUE(dual_device);
+
+  // Dual
+  ASSERT_EQ(DUAL, dual_device->GetDeviceType());
+  ASSERT_EQ(address_str, dual_device->GetUuid());
+
+  // Classic
+  ASSERT_EQ(DUAL, dual_device->GetClassicDevice()->GetDeviceType());
+  ASSERT_EQ(address_str, dual_device->GetClassicDevice()->GetUuid());
+
+  // LE
+  ASSERT_EQ(DUAL, dual_device->GetLeDevice()->GetDeviceType());
+  ASSERT_EQ(address_str, dual_device->GetLeDevice()->GetUuid());
+
+  ASSERT_TRUE(device_database_.CreateDualDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, remove_device) {
+  std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+  ASSERT_TRUE(created_device);
+  ASSERT_TRUE(device_database_.RemoveDevice(created_device));
+  ASSERT_TRUE(device_database_.CreateClassicDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, remove_device_twice) {
+  std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+  ASSERT_TRUE(device_database_.RemoveDevice(created_device));
+  ASSERT_FALSE(device_database_.RemoveDevice(created_device));
+}
+
+TEST_F(DeviceDatabaseTest, get_nonexistent_device) {
+  std::shared_ptr<Device> device_ptr = device_database_.GetClassicDevice(address_str);
+  ASSERT_FALSE(device_ptr);
+}
+
+TEST_F(DeviceDatabaseTest, address_modification_check) {
+  std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+  std::shared_ptr<Device> gotten_device = device_database_.GetClassicDevice(address.ToString());
+  ASSERT_TRUE(created_device);
+  ASSERT_TRUE(gotten_device);
+  ASSERT_EQ(address_str, created_device->GetAddress().ToString());
+  ASSERT_EQ(address_str, gotten_device->GetAddress().ToString());
+  device_database_.UpdateDeviceAddress(created_device, Address({0x01, 0x01, 0x01, 0x01, 0x01, 0x01}));
+  ASSERT_EQ("01:01:01:01:01:01", created_device->GetAddress().ToString());
+  ASSERT_EQ("01:01:01:01:01:01", gotten_device->GetAddress().ToString());
+  std::shared_ptr<Device> gotten_modified_device = device_database_.GetClassicDevice("01:01:01:01:01:01");
+  ASSERT_TRUE(gotten_modified_device);
+  ASSERT_TRUE(device_database_.RemoveDevice(gotten_modified_device));
+  ASSERT_FALSE(device_database_.GetClassicDevice("01:01:01:01:01:01"));
+}
+}  // namespace
+}  // namespace bluetooth::hci
diff --git a/gd/hci/device_test.cc b/gd/hci/device_test.cc
new file mode 100644
index 0000000..1b4fafc
--- /dev/null
+++ b/gd/hci/device_test.cc
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ *  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 "device.h"
+#include "classic_device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+static const char* test_addr_str = "bc:9a:78:56:34:12";
+static const uint8_t test_addr[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+static const Address address(test_addr);
+
+namespace bluetooth::hci {
+namespace {
+class TestableDevice : public Device {
+ public:
+  explicit TestableDevice(Address a) : Device(a, CLASSIC) {}
+
+  void SetTheAddress() {
+    Address a({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+    this->SetAddress(a);
+  }
+  void SetTheClassOfDevice() {
+    ClassOfDevice class_of_device({0x01, 0x02, 0x03});
+    this->SetClassOfDevice(class_of_device);
+  }
+  void SetTheName() {
+    std::string name = "Some Name";
+    this->SetName(name);
+  }
+  void SetTheIsBonded() {
+    this->SetIsBonded(true);
+  }
+};
+class DeviceTest : public ::testing::Test {
+ public:
+  DeviceTest() : device_(Address(test_addr)) {}
+
+ protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+  TestableDevice device_;
+};
+
+TEST_F(DeviceTest, initial_integrity) {
+  ASSERT_STREQ(test_addr_str, device_.GetAddress().ToString().c_str());
+  ASSERT_STREQ(test_addr_str, device_.GetUuid().c_str());
+  ASSERT_EQ(DeviceType::CLASSIC, device_.GetDeviceType());
+  ASSERT_EQ("", device_.GetName());
+}
+
+TEST_F(DeviceTest, set_get_class_of_device) {
+  ClassOfDevice class_of_device({0x01, 0x02, 0x03});
+  ASSERT_NE(class_of_device, device_.GetClassOfDevice());
+  device_.SetTheClassOfDevice();
+  ASSERT_EQ(class_of_device, device_.GetClassOfDevice());
+}
+
+TEST_F(DeviceTest, set_get_name) {
+  std::string name = "Some Name";
+  ASSERT_EQ("", device_.GetName());
+  device_.SetTheName();
+  ASSERT_EQ(name, device_.GetName());
+}
+
+TEST_F(DeviceTest, operator_iseq) {
+  TestableDevice d(address);
+  EXPECT_EQ(device_, d);
+}
+
+TEST_F(DeviceTest, set_address) {
+  ASSERT_EQ(test_addr_str, device_.GetAddress().ToString());
+  device_.SetTheAddress();
+  ASSERT_EQ("06:05:04:03:02:01", device_.GetAddress().ToString());
+}
+
+TEST_F(DeviceTest, set_bonded) {
+  ASSERT_FALSE(device_.IsBonded());
+  device_.SetTheIsBonded();
+  ASSERT_TRUE(device_.IsBonded());
+}
+
+}  // namespace
+}  // namespace bluetooth::hci
diff --git a/gd/hci/dual_device.h b/gd/hci/dual_device.h
new file mode 100644
index 0000000..8d08019
--- /dev/null
+++ b/gd/hci/dual_device.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  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 "hci/classic_device.h"
+#include "hci/device.h"
+#include "hci/le_device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * A device representing a DUAL device.
+ *
+ * <p>This can be a DUAL only.
+ */
+class DualDevice : public Device {
+ public:
+  std::shared_ptr<Device> GetClassicDevice() {
+    return classic_device_;
+  }
+
+  std::shared_ptr<Device> GetLeDevice() {
+    return le_device_;
+  }
+
+ protected:
+  friend class DeviceDatabase;
+  DualDevice(Address address, std::shared_ptr<ClassicDevice> classic_device, std::shared_ptr<LeDevice> le_device)
+      : Device(address, DUAL), classic_device_(std::move(classic_device)), le_device_(std::move(le_device)) {
+    classic_device_->SetDeviceType(DUAL);
+    le_device_->SetDeviceType(DUAL);
+  }
+
+  void SetAddress(Address address) override {
+    Device::SetAddress(address);
+    GetClassicDevice()->SetAddress(address);
+    GetLeDevice()->SetAddress(address);
+  }
+
+ private:
+  std::shared_ptr<ClassicDevice> classic_device_;
+  std::shared_ptr<LeDevice> le_device_;
+};
+
+}  // namespace bluetooth::hci
diff --git a/gd/hci/dual_device_test.cc b/gd/hci/dual_device_test.cc
new file mode 100644
index 0000000..1c4c2b0
--- /dev/null
+++ b/gd/hci/dual_device_test.cc
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ *  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 "dual_device.h"
+#include "device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+static const char* test_addr_str = "bc:9a:78:56:34:12";
+static const uint8_t test_addr[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+static const Address address(test_addr);
+
+namespace bluetooth::hci {
+namespace {
+class TestableClassicDevice : public ClassicDevice {
+ public:
+  explicit TestableClassicDevice(Address a) : ClassicDevice(a) {}
+};
+class TestableLeDevice : public LeDevice {
+ public:
+  explicit TestableLeDevice(Address a) : LeDevice(a) {}
+};
+class TestableDevice : public DualDevice {
+ public:
+  TestableDevice(Address a, std::shared_ptr<TestableClassicDevice>& classic_device,
+                 std::shared_ptr<TestableLeDevice>& le_device)
+      : DualDevice(a, classic_device, le_device) {}
+
+  void SetTheAddress() {
+    Address a({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+    this->SetAddress(a);
+  }
+};
+std::shared_ptr<TestableClassicDevice> classic_device = std::make_shared<TestableClassicDevice>(address);
+std::shared_ptr<TestableLeDevice> le_device = std::make_shared<TestableLeDevice>(address);
+class DualDeviceTest : public ::testing::Test {
+ public:
+  DualDeviceTest() : device_(Address(test_addr), classic_device, le_device) {}
+
+ protected:
+  void SetUp() override {}
+
+  void TearDown() override {}
+  TestableDevice device_;
+};
+
+TEST_F(DualDeviceTest, initial_integrity) {
+  Address a = device_.GetAddress();
+  ASSERT_EQ(test_addr_str, a.ToString());
+
+  ASSERT_EQ(DUAL, device_.GetClassicDevice()->GetDeviceType());
+  ASSERT_EQ(a.ToString(), device_.GetClassicDevice()->GetAddress().ToString());
+
+  ASSERT_EQ(DUAL, device_.GetLeDevice()->GetDeviceType());
+  ASSERT_EQ(a.ToString(), device_.GetLeDevice()->GetAddress().ToString());
+
+  device_.SetTheAddress();
+
+  ASSERT_EQ("06:05:04:03:02:01", device_.GetAddress().ToString());
+  ASSERT_EQ("06:05:04:03:02:01", device_.GetClassicDevice()->GetAddress().ToString());
+  ASSERT_EQ("06:05:04:03:02:01", device_.GetLeDevice()->GetAddress().ToString());
+}
+
+}  // namespace
+}  // namespace bluetooth::hci
diff --git a/gd/hci/facade.cc b/gd/hci/facade.cc
index 578d6d2..3aebcbb 100644
--- a/gd/hci/facade.cc
+++ b/gd/hci/facade.cc
@@ -24,6 +24,7 @@
 #include "common/blocking_queue.h"
 #include "grpc/grpc_event_stream.h"
 #include "hci/acl_manager.h"
+#include "hci/classic_security_manager.h"
 #include "hci/controller.h"
 #include "hci/facade.grpc.pb.h"
 #include "hci/hci_layer.h"
@@ -40,23 +41,20 @@
 namespace bluetooth {
 namespace hci {
 
-class AclManagerFacadeService : public AclManagerFacade::Service, public ::bluetooth::hci::ConnectionCallbacks {
+class AclManagerFacadeService : public AclManagerFacade::Service,
+                                public ::bluetooth::hci::ConnectionCallbacks,
+                                public ::bluetooth::hci::ConnectionManagementCallbacks,
+                                public ::bluetooth::hci::AclManagerCallbacks {
  public:
   AclManagerFacadeService(AclManager* acl_manager, Controller* controller, HciLayer* hci_layer,
                           ::bluetooth::os::Handler* facade_handler)
       : acl_manager_(acl_manager), controller_(controller), hci_layer_(hci_layer), facade_handler_(facade_handler) {
     acl_manager_->RegisterCallbacks(this, facade_handler_);
+    acl_manager_->RegisterAclManagerCallbacks(this, facade_handler_);
   }
 
   using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
 
-  ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-                                  ::bluetooth::facade::BluetoothAddress* response) override {
-    auto address = controller_->GetControllerMacAddress().ToString();
-    response->set_address(address);
-    return ::grpc::Status::OK;
-  }
-
   ::grpc::Status SetPageScanMode(::grpc::ServerContext* context, const ::bluetooth::hci::PageScanMode* request,
                                  ::google::protobuf::Empty* response) override {
     ScanEnable scan_enable = request->enabled() ? ScanEnable::PAGE_SCAN_ONLY : ScanEnable::NO_SCANS;
@@ -74,8 +72,8 @@
   ::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* remote,
                          ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
-    common::Address peer;
-    ASSERT(common::Address::FromString(remote->address(), peer));
+    Address peer;
+    ASSERT(Address::FromString(remote->address(), peer));
     acl_manager_->CreateConnection(peer);
     return ::grpc::Status::OK;
   }
@@ -83,24 +81,38 @@
   ::grpc::Status Disconnect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
                             ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
-    common::Address peer;
-    common::Address::FromString(request->address(), peer);
+    Address peer;
+    Address::FromString(request->address(), peer);
     auto connection = acl_connections_.find(request->address());
     if (connection == acl_connections_.end()) {
       LOG_ERROR("Invalid address");
       return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
     } else {
-      connection->second.Disconnect(DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+      connection->second->Disconnect(DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
       return ::grpc::Status::OK;
     }
   }
 
+  ::grpc::Status AuthenticationRequested(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+                                         ::google::protobuf::Empty* response) override {
+    Address peer;
+    Address::FromString(request->address(), peer);
+    auto connection = acl_connections_.find(request->address());
+    if (connection == acl_connections_.end()) {
+      LOG_ERROR("Invalid address");
+      return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+    } else {
+      connection->second->AuthenticationRequested();
+      return ::grpc::Status::OK;
+    }
+  };
+
   ::grpc::Status SendAclData(::grpc::ServerContext* context, const AclData* request,
                              ::google::protobuf::Empty* response) override {
     std::unique_lock<std::mutex> lock(mutex_);
     std::promise<void> promise;
     auto future = promise.get_future();
-    acl_connections_[request->remote().address()].GetAclQueueEnd()->RegisterEnqueue(
+    acl_connections_[request->remote().address()]->GetAclQueueEnd()->RegisterEnqueue(
         facade_handler_, common::Bind(&AclManagerFacadeService::enqueue_packet, common::Unretained(this),
                                       common::Unretained(request), common::Passed(std::move(promise))));
     future.wait();
@@ -108,7 +120,7 @@
   }
 
   std::unique_ptr<BasePacketBuilder> enqueue_packet(const AclData* request, std::promise<void> promise) {
-    acl_connections_[request->remote().address()].GetAclQueueEnd()->UnregisterEnqueue();
+    acl_connections_[request->remote().address()]->GetAclQueueEnd()->UnregisterEnqueue();
     std::string req_string = request->payload();
     std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
     packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
@@ -122,6 +134,101 @@
     return acl_stream_.HandleRequest(context, request, writer);
   }
 
+  ::grpc::Status TestInternalHciCommands(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                         ::google::protobuf::Empty* response) {
+    LocalVersionInformation local_version_information = controller_->GetControllerLocalVersionInformation();
+    LOG_DEBUG("local name : %s", controller_->GetControllerLocalName().c_str());
+    controller_->WriteLocalName("Device Under Test");
+    LOG_DEBUG("new local name : %s", controller_->GetControllerLocalName().c_str());
+    LOG_DEBUG("manufacturer name : %d", local_version_information.manufacturer_name_);
+    LOG_DEBUG("hci version : %x", (uint16_t)local_version_information.hci_version_);
+    LOG_DEBUG("lmp version : %x", (uint16_t)local_version_information.lmp_version_);
+    LOG_DEBUG("supported commands : %x", controller_->GetControllerLocalSupportedCommands()[0]);
+    LOG_DEBUG("local extended features :");
+
+    controller_->SetEventMask(0x00001FFFFFFFFFFF);
+    controller_->SetEventFilterInquiryResultAllDevices();
+    ClassOfDevice class_of_device({0xab, 0xcd, 0xef});
+    ClassOfDevice class_of_device_mask({0x12, 0x34, 0x56});
+    controller_->SetEventFilterInquiryResultClassOfDevice(class_of_device, class_of_device_mask);
+    Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+    controller_->SetEventFilterInquiryResultAddress(bdaddr);
+    controller_->SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag::AUTO_ACCEPT_OFF);
+    controller_->SetEventFilterConnectionSetupClassOfDevice(class_of_device, class_of_device_mask,
+                                                            AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_DISABLED);
+    controller_->SetEventFilterConnectionSetupAddress(bdaddr, AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED);
+    controller_->SetEventFilterClearAll();
+    controller_->HostBufferSize(0xFF00, 0xF1, 0xFF02, 0xFF03);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status TestInternalHciLeCommands(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                           ::google::protobuf::Empty* response) {
+    LOG_DEBUG("le data packet length : %d", controller_->GetControllerLeBufferSize().le_data_packet_length_);
+    LOG_DEBUG("total num le packets : %d", controller_->GetControllerLeBufferSize().total_num_le_packets_);
+    LOG_DEBUG("le supported max tx octets : %d",
+              controller_->GetControllerLeMaximumDataLength().supported_max_tx_octets_);
+    LOG_DEBUG("le supported max tx times : %d", controller_->GetControllerLeMaximumDataLength().supported_max_tx_time_);
+    LOG_DEBUG("le supported max rx octets : %d",
+              controller_->GetControllerLeMaximumDataLength().supported_max_rx_octets_);
+    LOG_DEBUG("le supported max rx times : %d", controller_->GetControllerLeMaximumDataLength().supported_max_rx_time_);
+    LOG_DEBUG("le maximum advertising data length %d", controller_->GetControllerLeMaximumAdvertisingDataLength());
+    LOG_DEBUG("le number of supported advertising sets %d",
+              controller_->GetControllerLeNumberOfSupportedAdverisingSets());
+
+    controller_->LeSetEventMask(0x000000000000001F);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status TestClassicConnectionManagementCommands(::grpc::ServerContext* context,
+                                                         const facade::BluetoothAddress* request,
+                                                         ::google::protobuf::Empty* response) {
+    Address peer;
+    Address::FromString(request->address(), peer);
+    auto connection = acl_connections_.find(request->address());
+    if (connection == acl_connections_.end()) {
+      LOG_ERROR("Invalid address");
+      return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+    } else {
+      // TODO add individual grpc command if necessary
+      connection->second->RoleDiscovery();
+      connection->second->WriteLinkPolicySettings(0x07);
+      connection->second->ReadLinkPolicySettings();
+      connection->second->SniffSubrating(0x1234, 0x1234, 0x1234);
+      connection->second->WriteAutomaticFlushTimeout(0x07FF);
+      connection->second->ReadAutomaticFlushTimeout();
+      connection->second->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
+      connection->second->ReadTransmitPowerLevel(TransmitPowerLevelType::MAXIMUM);
+      connection->second->WriteLinkSupervisionTimeout(0x5678);
+      connection->second->ReadLinkSupervisionTimeout();
+      connection->second->ReadFailedContactCounter();
+      connection->second->ResetFailedContactCounter();
+      connection->second->ReadLinkQuality();
+      connection->second->ReadAfhChannelMap();
+      connection->second->ReadRssi();
+      connection->second->ReadClock(WhichClock::LOCAL);
+      connection->second->ReadClock(WhichClock::PICONET);
+
+      connection->second->ChangeConnectionPacketType(0xEE1C);
+      connection->second->SetConnectionEncryption(Enable::ENABLED);
+      connection->second->ChangeConnectionLinkKey();
+      connection->second->ReadClockOffset();
+      connection->second->HoldMode(0x0500, 0x0020);
+      connection->second->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
+      connection->second->ExitSniffMode();
+      connection->second->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+      connection->second->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
+                                            0x1232, 0x1231);
+      connection->second->Flush();
+
+      acl_manager_->MasterLinkKey(KeyFlag::TEMPORARY);
+      acl_manager_->SwitchRole(peer, Role::MASTER);
+      acl_manager_->WriteDefaultLinkPolicySettings(0x07);
+      acl_manager_->ReadDefaultLinkPolicySettings();
+      return ::grpc::Status::OK;
+    }
+  }
+
   void on_incoming_acl(std::string address) {
     auto connection = acl_connections_.find(address);
     if (connection == acl_connections_.end()) {
@@ -129,7 +236,7 @@
       return;
     }
 
-    auto packet = connection->second.GetAclQueueEnd()->TryDequeue();
+    auto packet = connection->second->GetAclQueueEnd()->TryDequeue();
     auto acl_packet = AclPacketView::Create(*packet);
     AclData acl_data;
     acl_data.mutable_remote()->set_address(address);
@@ -138,14 +245,28 @@
     acl_stream_.OnIncomingEvent(acl_data);
   }
 
-  void OnConnectSuccess(::bluetooth::hci::AclConnection connection) override {
+  void OnConnectSuccess(std::unique_ptr<::bluetooth::hci::AclConnection> connection) override {
     std::unique_lock<std::mutex> lock(mutex_);
-    auto addr = connection.GetAddress();
-    acl_connections_.emplace(addr.ToString(), connection);
-    connection.RegisterDisconnectCallback(
+    auto addr = connection->GetAddress();
+    std::shared_ptr<::bluetooth::hci::AclConnection> shared_connection = std::move(connection);
+    acl_connections_.emplace(addr.ToString(), shared_connection);
+    shared_connection->RegisterDisconnectCallback(
         common::BindOnce(&AclManagerFacadeService::on_disconnect, common::Unretained(this), addr.ToString()),
         facade_handler_);
-    connection_complete_stream_.OnIncomingEvent(connection);
+    shared_connection->RegisterCallbacks(this, facade_handler_);
+    connection_complete_stream_.OnIncomingEvent(shared_connection);
+  }
+
+  void OnMasterLinkKeyComplete(uint16_t connection_handle, KeyFlag key_flag) override {
+    LOG_DEBUG("OnMasterLinkKeyComplete connection_handle:%d", connection_handle);
+  }
+
+  void OnRoleChange(Address bd_addr, Role new_role) override {
+    LOG_DEBUG("OnRoleChange bd_addr:%s, new_role:%d", bd_addr.ToString().c_str(), (uint8_t)new_role);
+  }
+
+  void OnReadDefaultLinkPolicySettingsComplete(uint16_t default_link_policy_settings) override {
+    LOG_DEBUG("OnReadDefaultLinkPolicySettingsComplete default_link_policy_settings:%d", default_link_policy_settings);
   }
 
   void on_disconnect(std::string address, ErrorCode code) {
@@ -161,7 +282,7 @@
     return connection_complete_stream_.HandleRequest(context, request, writer);
   };
 
-  void OnConnectFail(::bluetooth::common::Address address, ::bluetooth::hci::ErrorCode reason) override {
+  void OnConnectFail(Address address, ::bluetooth::hci::ErrorCode reason) override {
     std::unique_lock<std::mutex> lock(mutex_);
     ConnectionFailedEvent event;
     event.mutable_remote()->set_address(address.ToString());
@@ -169,6 +290,89 @@
     connection_failed_stream_.OnIncomingEvent(event);
   }
 
+  void OnConnectionPacketTypeChanged(uint16_t packet_type) override {
+    LOG_DEBUG("OnConnectionPacketTypeChanged packet_type:%d", packet_type);
+  }
+
+  void OnAuthenticationComplete() override {
+    LOG_DEBUG("OnAuthenticationComplete");
+  }
+
+  void OnEncryptionChange(EncryptionEnabled enabled) override {
+    LOG_DEBUG("OnConnectionPacketTypeChanged enabled:%d", (uint8_t)enabled);
+  }
+
+  void OnChangeConnectionLinkKeyComplete() override {
+    LOG_DEBUG("OnChangeConnectionLinkKeyComplete");
+  };
+
+  void OnReadClockOffsetComplete(uint16_t clock_offset) override {
+    LOG_DEBUG("OnReadClockOffsetComplete clock_offset:%d", clock_offset);
+  };
+
+  void OnModeChange(Mode current_mode, uint16_t interval) override {
+    LOG_DEBUG("OnModeChange Mode:%d, interval:%d", (uint8_t)current_mode, interval);
+  };
+
+  void OnQosSetupComplete(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+                          uint32_t delay_variation) override {
+    LOG_DEBUG("OnQosSetupComplete service_type:%d, token_rate:%d, peak_bandwidth:%d, latency:%d, delay_variation:%d",
+              (uint8_t)service_type, token_rate, peak_bandwidth, latency, delay_variation);
+  }
+
+  void OnFlowSpecificationComplete(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+                                   uint32_t token_bucket_size, uint32_t peak_bandwidth,
+                                   uint32_t access_latency) override {
+    LOG_DEBUG(
+        "OnFlowSpecificationComplete flow_direction:%d. service_type:%d, token_rate:%d, token_bucket_size:%d, "
+        "peak_bandwidth:%d, access_latency:%d",
+        (uint8_t)flow_direction, (uint8_t)service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency);
+  }
+
+  void OnFlushOccurred() override {
+    LOG_DEBUG("OnFlushOccurred");
+  }
+
+  void OnRoleDiscoveryComplete(Role current_role) override {
+    LOG_DEBUG("OnRoleDiscoveryComplete current_role:%d", (uint8_t)current_role);
+  }
+
+  void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {
+    LOG_DEBUG("OnReadLinkPolicySettingsComplete link_policy_settings:%d", link_policy_settings);
+  }
+
+  void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {
+    LOG_DEBUG("OnReadAutomaticFlushTimeoutComplete flush_timeout:%d", flush_timeout);
+  }
+
+  void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {
+    LOG_DEBUG("OnReadTransmitPowerLevelComplete transmit_power_level:%d", transmit_power_level);
+  }
+
+  void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {
+    LOG_DEBUG("OnReadLinkSupervisionTimeoutComplete link_supervision_timeout:%d", link_supervision_timeout);
+  }
+
+  void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {
+    LOG_DEBUG("OnReadFailedContactCounterComplete failed_contact_counter:%d", failed_contact_counter);
+  }
+
+  void OnReadLinkQualityComplete(uint8_t link_quality) override {
+    LOG_DEBUG("OnReadLinkQualityComplete link_quality:%d", link_quality);
+  }
+
+  void OnReadAfhChannelMapComplete(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) {
+    LOG_DEBUG("OnReadAfhChannelMapComplete afh_mode:%d", (uint8_t)afh_mode);
+  }
+
+  void OnReadRssiComplete(uint8_t rssi) override {
+    LOG_DEBUG("OnReadRssiComplete rssi:%d", rssi);
+  }
+
+  void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {
+    LOG_DEBUG("OnReadClockComplete clock:%d, accuracy:%d", clock, accuracy);
+  }
+
   ::grpc::Status FetchConnectionFailed(::grpc::ServerContext* context, const EventStreamRequest* request,
                                        ::grpc::ServerWriter<ConnectionFailedEvent>* writer) override {
     return connection_failed_stream_.HandleRequest(context, request, writer);
@@ -188,13 +392,14 @@
   ::bluetooth::os::Handler* facade_handler_;
 
   class ConnectionCompleteStreamCallback
-      : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionEvent, AclConnection> {
+      : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionEvent, std::shared_ptr<AclConnection>> {
    public:
-    void OnWriteResponse(ConnectionEvent* response, AclConnection const& connection) override {
-      response->mutable_remote()->set_address(connection.GetAddress().ToString());
+    void OnWriteResponse(ConnectionEvent* response, const std::shared_ptr<AclConnection>& connection) override {
+      response->mutable_remote()->set_address(connection->GetAddress().ToString());
+      response->set_connection_handle(connection->GetHandle());
     }
   } connection_complete_stream_callback_;
-  ::bluetooth::grpc::GrpcEventStream<ConnectionEvent, AclConnection> connection_complete_stream_{
+  ::bluetooth::grpc::GrpcEventStream<ConnectionEvent, std::shared_ptr<AclConnection>> connection_complete_stream_{
       &connection_complete_stream_callback_};
 
   class ConnectionFailedStreamCallback
@@ -224,7 +429,7 @@
     ~AclStreamCallback() {
       if (subscribed_) {
         for (const auto& connection : service_->acl_connections_) {
-          connection.second.GetAclQueueEnd()->UnregisterDequeue();
+          connection.second->GetAclQueueEnd()->UnregisterDequeue();
         }
         subscribed_ = false;
       }
@@ -236,8 +441,8 @@
         return;
       }
       for (const auto& connection : service_->acl_connections_) {
-        auto remote_address = connection.second.GetAddress().ToString();
-        connection.second.GetAclQueueEnd()->RegisterDequeue(
+        auto remote_address = connection.second->GetAddress().ToString();
+        connection.second->GetAclQueueEnd()->RegisterDequeue(
             service_->facade_handler_,
             common::Bind(&AclManagerFacadeService::on_incoming_acl, common::Unretained(service_), remote_address));
       }
@@ -250,7 +455,7 @@
         return;
       }
       for (const auto& connection : service_->acl_connections_) {
-        connection.second.GetAclQueueEnd()->UnregisterDequeue();
+        connection.second->GetAclQueueEnd()->UnregisterDequeue();
       }
       subscribed_ = false;
     }
@@ -265,7 +470,7 @@
   } acl_stream_callback_{this};
   ::bluetooth::grpc::GrpcEventStream<AclData, AclData> acl_stream_{&acl_stream_callback_};
 
-  std::map<std::string, AclConnection> acl_connections_;
+  std::map<std::string, std::shared_ptr<AclConnection>> acl_connections_;
 };
 
 void AclManagerFacadeModule::ListDependencies(ModuleList* list) {
@@ -293,5 +498,299 @@
 const ModuleFactory AclManagerFacadeModule::Factory =
     ::bluetooth::ModuleFactory([]() { return new AclManagerFacadeModule(); });
 
+class ClassicSecurityManagerFacadeService : public ClassicSecurityManagerFacade::Service,
+                                            public ::bluetooth::hci::ClassicSecurityCommandCallbacks {
+ public:
+  ClassicSecurityManagerFacadeService(ClassicSecurityManager* classic_security_manager, Controller* controller,
+                                      HciLayer* hci_layer, ::bluetooth::os::Handler* facade_handler)
+      : classic_security_manager_(classic_security_manager), facade_handler_(facade_handler) {
+    classic_security_manager_->RegisterCallbacks(this, facade_handler_);
+  }
+
+  ::grpc::Status LinkKeyRequestReply(::grpc::ServerContext* context,
+                                     const ::bluetooth::hci::LinkKeyRequestReplyMessage* request,
+                                     ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    common::LinkKey link_key;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    ASSERT(common::LinkKey::FromString(request->link_key(), link_key));
+    classic_security_manager_->LinkKeyRequestReply(peer, link_key);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status LinkKeyRequestNegativeReply(::grpc::ServerContext* context,
+                                             const ::bluetooth::facade::BluetoothAddress* request,
+                                             ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->LinkKeyRequestNegativeReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status PinCodeRequestReply(::grpc::ServerContext* context,
+                                     const ::bluetooth::hci::PinCodeRequestReplyMessage* request,
+                                     ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    uint8_t len = request->len();
+    std::string pin_code = request->pin_code();
+    classic_security_manager_->PinCodeRequestReply(peer, len, pin_code);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status PinCodeRequestNegativeReply(::grpc::ServerContext* context,
+                                             const ::bluetooth::facade::BluetoothAddress* request,
+                                             ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->PinCodeRequestNegativeReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status IoCapabilityRequestReply(::grpc::ServerContext* context,
+                                          const ::bluetooth::hci::IoCapabilityRequestReplyMessage* request,
+                                          ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    IoCapability io_capability = (IoCapability)request->io_capability();
+    OobDataPresent oob_present = (OobDataPresent)request->oob_present();
+    AuthenticationRequirements authentication_requirements =
+        (AuthenticationRequirements)request->authentication_requirements();
+    classic_security_manager_->IoCapabilityRequestReply(peer, io_capability, oob_present, authentication_requirements);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status IoCapabilityRequestNegativeReply(
+      ::grpc::ServerContext* context, const ::bluetooth::hci::IoCapabilityRequestNegativeReplyMessage* request,
+      ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    ErrorCode reason = (ErrorCode)request->reason();
+    classic_security_manager_->IoCapabilityRequestNegativeReply(peer, reason);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status UserConfirmationRequestReply(::grpc::ServerContext* context,
+                                              const ::bluetooth::facade::BluetoothAddress* request,
+                                              ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->UserConfirmationRequestReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status UserConfirmationRequestNegativeReply(::grpc::ServerContext* context,
+                                                      const ::bluetooth::facade::BluetoothAddress* request,
+                                                      ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->UserConfirmationRequestNegativeReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status UserPasskeyRequestReply(::grpc::ServerContext* context,
+                                         const ::bluetooth::hci::UserPasskeyRequestReplyMessage* request,
+                                         ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    uint32_t passkey = request->passkey();
+    classic_security_manager_->UserPasskeyRequestReply(peer, passkey);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status UserPasskeyRequestNegativeReply(::grpc::ServerContext* context,
+                                                 const ::bluetooth::facade::BluetoothAddress* request,
+                                                 ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->UserPasskeyRequestNegativeReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status RemoteOobDataRequestReply(::grpc::ServerContext* context,
+                                           const ::bluetooth::hci::RemoteOobDataRequestReplyMessage* request,
+                                           ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    std::string c_string = request->c();
+    std::string r_string = request->r();
+    std::array<uint8_t, 16> c;
+    std::array<uint8_t, 16> r;
+    std::copy(std::begin(c_string), std::end(c_string), std::begin(c));
+    std::copy(std::begin(r_string), std::end(r_string), std::begin(r));
+    classic_security_manager_->RemoteOobDataRequestReply(peer, c, r);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status RemoteOobDataRequestNegativeReply(::grpc::ServerContext* context,
+                                                   const ::bluetooth::facade::BluetoothAddress* request,
+                                                   ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->address(), peer));
+    classic_security_manager_->RemoteOobDataRequestNegativeReply(peer);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status ReadStoredLinkKey(::grpc::ServerContext* context,
+                                   const ::bluetooth::hci::ReadStoredLinkKeyMessage* request,
+                                   ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    ReadStoredLinkKeyReadAllFlag read_all_flag = (ReadStoredLinkKeyReadAllFlag)request->read_all_flag();
+    classic_security_manager_->ReadStoredLinkKey(peer, read_all_flag);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status WriteStoredLinkKey(::grpc::ServerContext* context,
+                                    const ::bluetooth::hci::WriteStoredLinkKeyMessage* request,
+                                    ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    uint8_t num_keys_to_write = request->num_keys_to_write();
+    std::vector<KeyAndAddress> keys;
+    for (size_t i = 0; i < num_keys_to_write; i++) {
+      KeyAndAddress key;
+      common::LinkKey link_key;
+      ASSERT(Address::FromString(request->remote().address(), key.address_));
+      ASSERT(common::LinkKey::FromString(request->link_keys(), link_key));
+      std::copy(std::begin(link_key.link_key), std::end(link_key.link_key), std::begin(key.link_key_));
+      keys.push_back(key);
+    }
+
+    classic_security_manager_->WriteStoredLinkKey(keys);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status DeleteStoredLinkKey(::grpc::ServerContext* context,
+                                     const ::bluetooth::hci::DeleteStoredLinkKeyMessage* request,
+                                     ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    DeleteStoredLinkKeyDeleteAllFlag delete_all_flag = (DeleteStoredLinkKeyDeleteAllFlag)request->delete_all_flag();
+    classic_security_manager_->DeleteStoredLinkKey(peer, delete_all_flag);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status RefreshEncryptionKey(::grpc::ServerContext* context,
+                                      const ::bluetooth::hci::RefreshEncryptionKeyMessage* request,
+                                      ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    classic_security_manager_->RefreshEncryptionKey(request->connection_handle());
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status ReadSimplePairingMode(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                       ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    classic_security_manager_->ReadSimplePairingMode();
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status WriteSimplePairingMode(::grpc::ServerContext* context,
+                                        const ::bluetooth::hci::WriteSimplePairingModeMessage* request,
+                                        ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Enable simple_pairing_mode = (Enable)request->simple_pairing_mode();
+    classic_security_manager_->WriteSimplePairingMode(simple_pairing_mode);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status ReadLocalOobData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                  ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    classic_security_manager_->ReadLocalOobData();
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status SendKeypressNotification(::grpc::ServerContext* context,
+                                          const ::bluetooth::hci::SendKeypressNotificationMessage* request,
+                                          ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    Address peer;
+    ASSERT(Address::FromString(request->remote().address(), peer));
+    KeypressNotificationType notification_type = (KeypressNotificationType)request->notification_type();
+    classic_security_manager_->SendKeypressNotification(peer, notification_type);
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status ReadLocalOobExtendedData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+                                          ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    classic_security_manager_->ReadLocalOobExtendedData();
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status ReadEncryptionKeySize(::grpc::ServerContext* context,
+                                       const ::bluetooth::hci::ReadEncryptionKeySizeMessage* request,
+                                       ::google::protobuf::Empty* response) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    classic_security_manager_->ReadEncryptionKeySize(request->connection_handle());
+    return ::grpc::Status::OK;
+  };
+
+  ::grpc::Status FetchCommandCompleteEvent(::grpc::ServerContext* context, const EventStreamRequest* request,
+                                           ::grpc::ServerWriter<CommandCompleteEvent>* writer) override {
+    return command_complete_stream_.HandleRequest(context, request, writer);
+  };
+
+  void OnCommandComplete(CommandCompleteView status) override {
+    std::unique_lock<std::mutex> lock(mutex_);
+    command_complete_stream_.OnIncomingEvent(status);
+  }
+
+ private:
+  ClassicSecurityManager* classic_security_manager_;
+  mutable std::mutex mutex_;
+  ::bluetooth::os::Handler* facade_handler_;
+
+  class CommandCompleteStreamCallback
+      : public ::bluetooth::grpc::GrpcEventStreamCallback<CommandCompleteEvent, CommandCompleteView> {
+   public:
+    void OnWriteResponse(CommandCompleteEvent* response, CommandCompleteView const& status) override {
+      response->set_command_opcode((uint32_t)status.GetCommandOpCode());
+    }
+  } command_complete_stream_callback_;
+  ::bluetooth::grpc::GrpcEventStream<CommandCompleteEvent, CommandCompleteView> command_complete_stream_{
+      &command_complete_stream_callback_};
+};
+
+void ClassicSecurityManagerFacadeModule::ListDependencies(ModuleList* list) {
+  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+  list->add<ClassicSecurityManager>();
+  list->add<Controller>();
+  list->add<HciLayer>();
+}
+
+void ClassicSecurityManagerFacadeModule::Start() {
+  ::bluetooth::grpc::GrpcFacadeModule::Start();
+  service_ = new ClassicSecurityManagerFacadeService(
+      GetDependency<ClassicSecurityManager>(), GetDependency<Controller>(), GetDependency<HciLayer>(), GetHandler());
+}
+
+void ClassicSecurityManagerFacadeModule::Stop() {
+  delete service_;
+  ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* ClassicSecurityManagerFacadeModule::GetService() const {
+  return service_;
+}
+
+const ModuleFactory ClassicSecurityManagerFacadeModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new ClassicSecurityManagerFacadeModule(); });
+
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/hci/facade.h b/gd/hci/facade.h
index 289d00b..b38286d 100644
--- a/gd/hci/facade.h
+++ b/gd/hci/facade.h
@@ -39,5 +39,20 @@
   AclManagerFacadeService* service_;
 };
 
+class ClassicSecurityManagerFacadeService;
+
+class ClassicSecurityManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+  static const ModuleFactory Factory;
+
+  void ListDependencies(ModuleList* list) override;
+  void Start() override;
+  void Stop() override;
+  ::grpc::Service* GetService() const override;
+
+ private:
+  ClassicSecurityManagerFacadeService* service_;
+};
+
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/hci/facade.proto b/gd/hci/facade.proto
index 9067260..b9899e6 100644
--- a/gd/hci/facade.proto
+++ b/gd/hci/facade.proto
@@ -6,15 +6,18 @@
 import "facade/common.proto";
 
 service AclManagerFacade {
-  rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
   rpc SetPageScanMode(PageScanMode) returns (google.protobuf.Empty) {}
   rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
   rpc Disconnect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc AuthenticationRequested(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
   rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionEvent) {}
   rpc FetchDisconnection(facade.EventStreamRequest) returns (stream DisconnectionEvent) {}
   rpc FetchConnectionFailed(facade.EventStreamRequest) returns (stream ConnectionFailedEvent) {}
   rpc SendAclData(AclData) returns (google.protobuf.Empty) {}
   rpc FetchAclData(facade.EventStreamRequest) returns (stream AclData) {}
+  rpc TestInternalHciCommands(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc TestInternalHciLeCommands(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc TestClassicConnectionManagementCommands(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
 }
 
 message PageScanMode {
@@ -23,6 +26,7 @@
 
 message ConnectionEvent {
   facade.BluetoothAddress remote = 1;
+  uint32 connection_handle = 2;
 }
 
 message DisconnectionEvent {
@@ -39,3 +43,116 @@
   facade.BluetoothAddress remote = 1;
   bytes payload = 2;
 }
+
+service ClassicPairingFacade {
+  rpc SetPairingMode(PairingMode) returns (google.protobuf.Empty) {}
+  rpc DeletePairing(DeletePairingRequest) returns (google.protobuf.Empty) {}
+}
+
+message PairingMode {
+  bool enabled = 1;
+}
+
+message DeletePairingRequest {
+  bool deleteAll = 1;
+  facade.BluetoothAddress remote = 2;
+}
+
+service ClassicSecurityManagerFacade {
+  rpc LinkKeyRequestReply(LinkKeyRequestReplyMessage) returns (google.protobuf.Empty) {}
+  rpc LinkKeyRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc PinCodeRequestReply(PinCodeRequestReplyMessage) returns (google.protobuf.Empty) {}
+  rpc PinCodeRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc IoCapabilityRequestReply(IoCapabilityRequestReplyMessage) returns (google.protobuf.Empty) {}
+  rpc IoCapabilityRequestNegativeReply(IoCapabilityRequestNegativeReplyMessage) returns (google.protobuf.Empty) {}
+  rpc UserConfirmationRequestReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc UserConfirmationRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc UserPasskeyRequestReply(UserPasskeyRequestReplyMessage) returns (google.protobuf.Empty) {}
+  rpc UserPasskeyRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc RemoteOobDataRequestReply(RemoteOobDataRequestReplyMessage) returns (google.protobuf.Empty) {}
+  rpc RemoteOobDataRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc ReadStoredLinkKey(ReadStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+  rpc WriteStoredLinkKey(WriteStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+  rpc DeleteStoredLinkKey(DeleteStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+  rpc RefreshEncryptionKey(RefreshEncryptionKeyMessage) returns (google.protobuf.Empty) {}
+  rpc ReadSimplePairingMode(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc WriteSimplePairingMode(WriteSimplePairingModeMessage) returns (google.protobuf.Empty) {}
+  rpc ReadLocalOobData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc SendKeypressNotification(SendKeypressNotificationMessage) returns (google.protobuf.Empty) {}
+  rpc ReadLocalOobExtendedData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+  rpc ReadEncryptionKeySize(ReadEncryptionKeySizeMessage) returns (google.protobuf.Empty) {}
+
+  rpc FetchCommandCompleteEvent(facade.EventStreamRequest) returns (stream CommandCompleteEvent) {}
+}
+
+
+message CommandCompleteEvent {
+  uint32 command_opcode = 1;
+}
+
+message LinkKeyRequestReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  bytes link_key = 2;
+}
+
+message PinCodeRequestReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 len = 2;
+  bytes pin_code = 3;
+}
+
+message IoCapabilityRequestReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 io_capability = 2;
+  uint32 oob_present = 3;
+  uint32 authentication_requirements = 4;
+}
+
+message IoCapabilityRequestNegativeReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 reason = 2;
+}
+
+message UserPasskeyRequestReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 passkey = 2;
+}
+
+message RemoteOobDataRequestReplyMessage {
+  facade.BluetoothAddress remote = 1;
+  bytes c = 2;
+  bytes r = 3;
+}
+
+message ReadStoredLinkKeyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 read_all_flag = 2;
+}
+
+message WriteStoredLinkKeyMessage {
+  uint32 num_keys_to_write = 1;
+  facade.BluetoothAddress remote = 2;
+  bytes link_keys = 3;
+}
+
+message DeleteStoredLinkKeyMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 delete_all_flag = 2;
+}
+
+message RefreshEncryptionKeyMessage {
+  uint32 connection_handle = 1;
+}
+
+message WriteSimplePairingModeMessage {
+  uint32 simple_pairing_mode = 1;
+}
+
+message SendKeypressNotificationMessage {
+  facade.BluetoothAddress remote = 1;
+  uint32 notification_type = 2;
+}
+
+message ReadEncryptionKeySizeMessage {
+  uint32 connection_handle = 1;
+}
\ No newline at end of file
diff --git a/gd/hci/hci_layer.cc b/gd/hci/hci_layer.cc
index fc41fe4..5d903de 100644
--- a/gd/hci/hci_layer.cc
+++ b/gd/hci/hci_layer.cc
@@ -33,6 +33,7 @@
 using bluetooth::hci::CommandPacketBuilder;
 using bluetooth::hci::CommandStatusView;
 using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeMetaEventView;
 using bluetooth::os::Handler;
 
 class EventHandler {
@@ -44,6 +45,15 @@
   Handler* handler;
 };
 
+class SubeventHandler {
+ public:
+  SubeventHandler() : subevent_handler(), handler(nullptr) {}
+  SubeventHandler(Callback<void(LeMetaEventView)> on_event, Handler* on_event_handler)
+      : subevent_handler(std::move(on_event)), handler(on_event_handler) {}
+  Callback<void(LeMetaEventView)> subevent_handler;
+  Handler* handler;
+};
+
 class CommandQueueEntry {
  public:
   CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
@@ -67,7 +77,6 @@
 namespace bluetooth {
 namespace hci {
 
-using common::Address;
 using common::BidiQueue;
 using common::BidiQueueEnd;
 using os::Alarm;
@@ -88,6 +97,78 @@
 }
 }  // namespace
 
+class SecurityInterfaceImpl : public SecurityInterface {
+ public:
+  SecurityInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+  virtual ~SecurityInterfaceImpl() = default;
+
+  virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete,
+                              os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+  }
+
+  virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+  }
+  HciLayer& hci_;
+};
+
+class LeSecurityInterfaceImpl : public LeSecurityInterface {
+ public:
+  LeSecurityInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+  virtual ~LeSecurityInterfaceImpl() = default;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete,
+                              os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+  }
+
+  virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+  }
+  HciLayer& hci_;
+};
+
+class LeAdvertisingInterfaceImpl : public LeAdvertisingInterface {
+ public:
+  LeAdvertisingInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+  virtual ~LeAdvertisingInterfaceImpl() = default;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete,
+                              os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+  }
+
+  virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+  }
+  HciLayer& hci_;
+};
+
+class LeScanningInterfaceImpl : public LeScanningInterface {
+ public:
+  LeScanningInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+  virtual ~LeScanningInterfaceImpl() = default;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete,
+                              os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+  }
+
+  virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+  }
+  HciLayer& hci_;
+};
+
 struct HciLayer::impl : public hal::HciHalCallbacks {
   impl(HciLayer& module) : hal_(nullptr), module_(module) {}
 
@@ -104,10 +185,9 @@
                          handler);
     RegisterEventHandler(EventCode::COMMAND_STATUS, Bind(&impl::command_status_callback, common::Unretained(this)),
                          handler);
-    // TODO find the right place
-    RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGE, Bind(&impl::drop, common::Unretained(this)),
+    RegisterEventHandler(EventCode::LE_META_EVENT, Bind(&impl::le_meta_event_callback, common::Unretained(this)),
                          handler);
-    RegisterEventHandler(EventCode::ROLE_CHANGE, Bind(&impl::drop, common::Unretained(this)), handler);
+    // TODO find the right place
     RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, Bind(&impl::drop, common::Unretained(this)),
                          handler);
     RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, Bind(&impl::drop, common::Unretained(this)), handler);
@@ -188,13 +268,23 @@
                "Waiting for command status 0x%02hx (%s), got command complete for 0x%02hx (%s)", waiting_command_,
                OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
     auto caller_handler = command_queue_.front().caller_handler;
-    caller_handler->Post(BindOnce(std::move(command_queue_.front().on_complete), std::move(complete_view)));
+    caller_handler->Post(BindOnce(std::move(command_queue_.front().on_complete), complete_view));
     command_queue_.pop_front();
     waiting_command_ = OpCode::NONE;
     hci_timeout_alarm_->Cancel();
     send_next_command();
   }
 
+  void le_meta_event_callback(EventPacketView event) {
+    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+    ASSERT(meta_event_view.IsValid());
+    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+    ASSERT_LOG(subevent_handlers_.find(subevent_code) != subevent_handlers_.end(),
+               "Unhandled le event of type 0x%02hhx (%s)", subevent_code, SubeventCodeText(subevent_code).c_str());
+    auto& registered_handler = subevent_handlers_[subevent_code].subevent_handler;
+    subevent_handlers_[subevent_code].handler->Post(BindOnce(registered_handler, meta_event_view));
+  }
+
   void hciEventReceived(hal::HciPacket event_bytes) override {
     auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
     EventPacketView event = EventPacketView::Create(packet);
@@ -206,7 +296,7 @@
   void hci_event_received_handler(EventPacketView event) {
     EventCode event_code = event.GetEventCode();
     ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx (%s)",
-               event.GetEventCode(), EventCodeText(event.GetEventCode()).c_str());
+               event_code, EventCodeText(event_code).c_str());
     auto& registered_handler = event_handlers_[event_code].event_handler;
     event_handlers_[event_code].handler->Post(BindOnce(registered_handler, std::move(event)));
   }
@@ -283,8 +373,8 @@
 
   void handle_register_event_handler(EventCode event_code, Callback<void(EventPacketView)> event_handler,
                                      os::Handler* handler) {
-    ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx",
-               event_code);
+    ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx (%s)",
+               event_code, EventCodeText(event_code).c_str());
     EventHandler to_save(event_handler, handler);
     event_handlers_[event_code] = to_save;
   }
@@ -298,16 +388,47 @@
     event_handlers_.erase(event_code);
   }
 
+  void RegisterLeEventHandler(SubeventCode subevent_code, Callback<void(LeMetaEventView)> event_handler,
+                              os::Handler* handler) {
+    module_.GetHandler()->Post(common::BindOnce(&impl::handle_register_le_event_handler, common::Unretained(this),
+                                                subevent_code, event_handler, common::Unretained(handler)));
+  }
+
+  void handle_register_le_event_handler(SubeventCode subevent_code, Callback<void(LeMetaEventView)> subevent_handler,
+                                        os::Handler* handler) {
+    ASSERT_LOG(subevent_handlers_.count(subevent_code) == 0,
+               "Can not register a second handler for subevent_code %02hhx (%s)", subevent_code,
+               SubeventCodeText(subevent_code).c_str());
+    SubeventHandler to_save(subevent_handler, handler);
+    subevent_handlers_[subevent_code] = to_save;
+  }
+
+  void UnregisterLeEventHandler(SubeventCode subevent_code) {
+    module_.GetHandler()->Post(
+        common::BindOnce(&impl::handle_unregister_le_event_handler, common::Unretained(this), subevent_code));
+  }
+
+  void handle_unregister_le_event_handler(SubeventCode subevent_code) {
+    subevent_handlers_.erase(subevent_code);
+  }
+
   // The HAL
   hal::HciHal* hal_;
 
   // A reference to the HciLayer module
   HciLayer& module_;
 
+  // Interfaces
+  SecurityInterfaceImpl security_interface{module_};
+  LeSecurityInterfaceImpl le_security_interface{module_};
+  LeAdvertisingInterfaceImpl le_advertising_interface{module_};
+  LeScanningInterfaceImpl le_scanning_interface{module_};
+
   // Command Handling
   std::list<CommandQueueEntry> command_queue_;
 
   std::map<EventCode, EventHandler> event_handlers_;
+  std::map<SubeventCode, SubeventHandler> subevent_handlers_;
   OpCode waiting_command_{OpCode::NONE};
   uint8_t command_credits_{1};  // Send reset first
   Alarm* hci_timeout_alarm_{nullptr};
@@ -346,6 +467,47 @@
   impl_->UnregisterEventHandler(event_code);
 }
 
+void HciLayer::RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+                                      os::Handler* handler) {
+  impl_->RegisterLeEventHandler(subevent_code, std::move(event_handler), handler);
+}
+
+void HciLayer::UnregisterLeEventHandler(SubeventCode subevent_code) {
+  impl_->UnregisterLeEventHandler(subevent_code);
+}
+
+SecurityInterface* HciLayer::GetSecurityInterface(common::Callback<void(EventPacketView)> event_handler,
+                                                  os::Handler* handler) {
+  for (const auto event : SecurityInterface::SecurityEvents) {
+    RegisterEventHandler(event, event_handler, handler);
+  }
+  return &impl_->security_interface;
+}
+
+LeSecurityInterface* HciLayer::GetLeSecurityInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                                      os::Handler* handler) {
+  for (const auto subevent : LeSecurityInterface::LeSecurityEvents) {
+    RegisterLeEventHandler(subevent, event_handler, handler);
+  }
+  return &impl_->le_security_interface;
+}
+
+LeAdvertisingInterface* HciLayer::GetLeAdvertisingInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                                            os::Handler* handler) {
+  for (const auto subevent : LeAdvertisingInterface::LeAdvertisingEvents) {
+    RegisterLeEventHandler(subevent, event_handler, handler);
+  }
+  return &impl_->le_advertising_interface;
+}
+
+LeScanningInterface* HciLayer::GetLeScanningInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                                      os::Handler* handler) {
+  for (const auto subevent : LeScanningInterface::LeScanningEvents) {
+    RegisterLeEventHandler(subevent, event_handler, handler);
+  }
+  return &impl_->le_scanning_interface;
+}
+
 const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
 
 void HciLayer::ListDependencies(ModuleList* list) {
@@ -359,5 +521,9 @@
 void HciLayer::Stop() {
   impl_->Stop();
 }
+
+std::string HciLayer::ToString() const {
+  return "Hci Layer";
+}
 }  // namespace hci
 }  // namespace bluetooth
diff --git a/gd/hci/hci_layer.h b/gd/hci/hci_layer.h
index 4aa3070..3e299d4 100644
--- a/gd/hci/hci_layer.h
+++ b/gd/hci/hci_layer.h
@@ -19,12 +19,16 @@
 #include <chrono>
 #include <map>
 
-#include "common/address.h"
+#include "address.h"
+#include "class_of_device.h"
 #include "common/bidi_queue.h"
 #include "common/callback.h"
-#include "common/class_of_device.h"
 #include "hal/hci_hal.h"
 #include "hci/hci_packets.h"
+#include "hci/le_advertising_interface.h"
+#include "hci/le_scanning_interface.h"
+#include "hci/le_security_interface.h"
+#include "hci/security_interface.h"
 #include "module.h"
 #include "os/utils.h"
 
@@ -50,6 +54,22 @@
 
   virtual void UnregisterEventHandler(EventCode event_code);
 
+  virtual void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+                                      os::Handler* handler);
+
+  virtual void UnregisterLeEventHandler(SubeventCode subevent_code);
+
+  SecurityInterface* GetSecurityInterface(common::Callback<void(EventPacketView)> event_handler, os::Handler* handler);
+
+  LeSecurityInterface* GetLeSecurityInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                              os::Handler* handler);
+
+  LeAdvertisingInterface* GetLeAdvertisingInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                                    os::Handler* handler);
+
+  LeScanningInterface* GetLeScanningInterface(common::Callback<void(LeMetaEventView)> event_handler,
+                                              os::Handler* handler);
+
   static const ModuleFactory Factory;
 
   void ListDependencies(ModuleList* list) override;
@@ -57,6 +77,8 @@
   void Start() override;
 
   void Stop() override;
+
+  std::string ToString() const override;
   static constexpr std::chrono::milliseconds kHciTimeoutMs = std::chrono::milliseconds(2000);
 
  private:
diff --git a/gd/hci/hci_layer_test.cc b/gd/hci/hci_layer_test.cc
index 51cf3bf..d796488 100644
--- a/gd/hci/hci_layer_test.cc
+++ b/gd/hci/hci_layer_test.cc
@@ -158,6 +158,26 @@
                          GetHandler());
   }
 
+  void SendSecurityCommandExpectingComplete(std::unique_ptr<SecurityCommandBuilder> command) {
+    if (security_interface_ == nullptr) {
+      security_interface_ = hci_->GetSecurityInterface(
+          common::Bind(&DependsOnHci::handle_event<EventPacketView>, common::Unretained(this)), GetHandler());
+    }
+    hci_->EnqueueCommand(std::move(command),
+                         common::Bind(&DependsOnHci::handle_event<CommandCompleteView>, common::Unretained(this)),
+                         GetHandler());
+  }
+
+  void SendLeSecurityCommandExpectingComplete(std::unique_ptr<LeSecurityCommandBuilder> command) {
+    if (le_security_interface_ == nullptr) {
+      le_security_interface_ = hci_->GetLeSecurityInterface(
+          common::Bind(&DependsOnHci::handle_event<LeMetaEventView>, common::Unretained(this)), GetHandler());
+    }
+    hci_->EnqueueCommand(std::move(command),
+                         common::Bind(&DependsOnHci::handle_event<CommandCompleteView>, common::Unretained(this)),
+                         GetHandler());
+  }
+
   void SendAclData(std::unique_ptr<AclPacketBuilder> acl) {
     outgoing_acl_.push(std::move(acl));
     auto queue_end = hci_->GetAclQueueEnd();
@@ -177,7 +197,7 @@
   }
 
   std::future<void> GetReceivedAclFuture() {
-    ASSERT_LOG(event_promise_ == nullptr, "Promises promises ... Only one at a time");
+    ASSERT_LOG(acl_promise_ == nullptr, "Promises promises ... Only one at a time");
     acl_promise_ = std::make_unique<std::promise<void>>();
     return acl_promise_->get_future();
   }
@@ -197,6 +217,9 @@
     hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
                                common::Bind(&DependsOnHci::handle_event<EventPacketView>, common::Unretained(this)),
                                GetHandler());
+    hci_->RegisterLeEventHandler(SubeventCode::CONNECTION_COMPLETE,
+                                 common::Bind(&DependsOnHci::handle_event<LeMetaEventView>, common::Unretained(this)),
+                                 GetHandler());
     hci_->GetAclQueueEnd()->RegisterDequeue(GetHandler(),
                                             common::Bind(&DependsOnHci::handle_acl, common::Unretained(this)));
   }
@@ -213,6 +236,8 @@
 
  private:
   HciLayer* hci_ = nullptr;
+  const SecurityInterface* security_interface_;
+  const LeSecurityInterface* le_security_interface_;
   std::list<EventPacketView> incoming_events_;
   std::list<AclPacketView> incoming_acl_packets_;
   std::unique_ptr<std::promise<void>> event_promise_;
@@ -308,6 +333,31 @@
 
 TEST_F(HciTest, initAndClose) {}
 
+TEST_F(HciTest, leMetaEvent) {
+  auto event_future = upper->GetReceivedEventFuture();
+
+  // Send an LE event
+  ErrorCode status = ErrorCode::SUCCESS;
+  uint16_t handle = 0x123;
+  Role role = Role::MASTER;
+  AddressType peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+  Address peer_address = Address::kAny;
+  uint16_t conn_interval = 0x0ABC;
+  uint16_t conn_latency = 0x0123;
+  uint16_t supervision_timeout = 0x0B05;
+  MasterClockAccuracy master_clock_accuracy = MasterClockAccuracy::PPM_50;
+  hal->callbacks->hciEventReceived(GetPacketBytes(
+      LeConnectionCompleteBuilder::Create(status, handle, role, peer_address_type, peer_address, conn_interval,
+                                          conn_latency, supervision_timeout, master_clock_accuracy)));
+
+  // Wait for the event
+  auto event_status = event_future.wait_for(kTimeout);
+  ASSERT_EQ(event_status, std::future_status::ready);
+
+  auto event = upper->GetReceivedEvent();
+  ASSERT(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventPacketView::Create(event))).IsValid());
+}
+
 TEST_F(HciTest, noOpCredits) {
   ASSERT_EQ(0, hal->GetNumSentCommands());
 
@@ -334,13 +384,14 @@
 
   // Send the response event
   ErrorCode error_code = ErrorCode::SUCCESS;
-  HciVersion hci_version = HciVersion::V_5_0;
-  uint16_t hci_subversion = 0x1234;
-  LmpVersion lmp_version = LmpVersion::V_4_2;
-  uint16_t manufacturer_name = 0xBAD;
-  uint16_t lmp_subversion = 0x5678;
-  hal->callbacks->hciEventReceived(GetPacketBytes(ReadLocalVersionInformationCompleteBuilder::Create(
-      num_packets, error_code, hci_version, hci_subversion, lmp_version, manufacturer_name, lmp_subversion)));
+  LocalVersionInformation local_version_information;
+  local_version_information.hci_version_ = HciVersion::V_5_0;
+  local_version_information.hci_revision_ = 0x1234;
+  local_version_information.lmp_version_ = LmpVersion::V_4_2;
+  local_version_information.manufacturer_name_ = 0xBAD;
+  local_version_information.lmp_subversion_ = 0x5678;
+  hal->callbacks->hciEventReceived(GetPacketBytes(
+      ReadLocalVersionInformationCompleteBuilder::Create(num_packets, error_code, local_version_information)));
 
   // Wait for the event
   auto event_status = event_future.wait_for(kTimeout);
@@ -380,13 +431,14 @@
   // Send the response event
   uint8_t num_packets = 1;
   ErrorCode error_code = ErrorCode::SUCCESS;
-  HciVersion hci_version = HciVersion::V_5_0;
-  uint16_t hci_subversion = 0x1234;
-  LmpVersion lmp_version = LmpVersion::V_4_2;
-  uint16_t manufacturer_name = 0xBAD;
-  uint16_t lmp_subversion = 0x5678;
-  hal->callbacks->hciEventReceived(GetPacketBytes(ReadLocalVersionInformationCompleteBuilder::Create(
-      num_packets, error_code, hci_version, hci_subversion, lmp_version, manufacturer_name, lmp_subversion)));
+  LocalVersionInformation local_version_information;
+  local_version_information.hci_version_ = HciVersion::V_5_0;
+  local_version_information.hci_revision_ = 0x1234;
+  local_version_information.lmp_version_ = LmpVersion::V_4_2;
+  local_version_information.manufacturer_name_ = 0xBAD;
+  local_version_information.lmp_subversion_ = 0x5678;
+  hal->callbacks->hciEventReceived(GetPacketBytes(
+      ReadLocalVersionInformationCompleteBuilder::Create(num_packets, error_code, local_version_information)));
 
   // Wait for the event
   auto event_status = event_future.wait_for(kTimeout);
@@ -450,11 +502,71 @@
              .IsValid());
 }
 
+TEST_F(HciTest, leSecurityInterfaceTest) {
+  // Send LeRand to the controller
+  auto command_future = hal->GetSentCommandFuture();
+  upper->SendLeSecurityCommandExpectingComplete(LeRandBuilder::Create());
+
+  auto command_sent_status = command_future.wait_for(kTimeout);
+  ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+  // Check the command
+  auto sent_command = hal->GetSentCommand();
+  ASSERT_LT(0, sent_command.size());
+  LeRandView view = LeRandView::Create(LeSecurityCommandView::Create(CommandPacketView::Create(sent_command)));
+  ASSERT_TRUE(view.IsValid());
+
+  // Send a Command Complete to the host
+  auto event_future = upper->GetReceivedEventFuture();
+  uint8_t num_packets = 1;
+  ErrorCode status = ErrorCode::SUCCESS;
+  uint64_t rand = 0x0123456789abcdef;
+  hal->callbacks->hciEventReceived(GetPacketBytes(LeRandCompleteBuilder::Create(num_packets, status, rand)));
+
+  // Verify the event
+  auto event_status = event_future.wait_for(kTimeout);
+  ASSERT_EQ(event_status, std::future_status::ready);
+  auto event = upper->GetReceivedEvent();
+  ASSERT_TRUE(event.IsValid());
+  ASSERT_EQ(EventCode::COMMAND_COMPLETE, event.GetEventCode());
+  ASSERT_TRUE(LeRandCompleteView::Create(CommandCompleteView::Create(event)).IsValid());
+}
+
+TEST_F(HciTest, securityInterfacesTest) {
+  // Send WriteSimplePairingMode to the controller
+  auto command_future = hal->GetSentCommandFuture();
+  Enable enable = Enable::ENABLED;
+  upper->SendSecurityCommandExpectingComplete(WriteSimplePairingModeBuilder::Create(enable));
+
+  auto command_sent_status = command_future.wait_for(kTimeout);
+  ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+  // Check the command
+  auto sent_command = hal->GetSentCommand();
+  ASSERT_LT(0, sent_command.size());
+  auto view = WriteSimplePairingModeView::Create(SecurityCommandView::Create(CommandPacketView::Create(sent_command)));
+  ASSERT_TRUE(view.IsValid());
+
+  // Send a Command Complete to the host
+  auto event_future = upper->GetReceivedEventFuture();
+  uint8_t num_packets = 1;
+  ErrorCode status = ErrorCode::SUCCESS;
+  hal->callbacks->hciEventReceived(GetPacketBytes(WriteSimplePairingModeCompleteBuilder::Create(num_packets, status)));
+
+  // Verify the event
+  auto event_status = event_future.wait_for(kTimeout);
+  ASSERT_EQ(event_status, std::future_status::ready);
+  auto event = upper->GetReceivedEvent();
+  ASSERT_TRUE(event.IsValid());
+  ASSERT_EQ(EventCode::COMMAND_COMPLETE, event.GetEventCode());
+  ASSERT_TRUE(WriteSimplePairingModeCompleteView::Create(CommandCompleteView::Create(event)).IsValid());
+}
+
 TEST_F(HciTest, createConnectionTest) {
   // Send CreateConnection to the controller
   auto command_future = hal->GetSentCommandFuture();
-  common::Address bd_addr;
-  ASSERT_TRUE(common::Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
+  Address bd_addr;
+  ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
   uint16_t packet_type = 0x1234;
   PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
   uint16_t clock_offset = 0x3456;
@@ -513,7 +625,7 @@
   ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());
 
   // Send an ACL packet from the remote
-  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
+  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
   BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
   auto acl_payload = std::make_unique<RawBuilder>();
   acl_payload->AddAddress(bd_addr);
@@ -533,7 +645,7 @@
   ASSERT_EQ(handle, itr.extract<uint16_t>());
 
   // Send an ACL packet from DependsOnHci
-  PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::COMPLETE_PDU;
+  PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
   BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
   auto acl_payload2 = std::make_unique<RawBuilder>();
   acl_payload2->AddOctets2(handle);
@@ -555,11 +667,11 @@
 }
 
 TEST_F(HciTest, receiveMultipleAclPackets) {
-  common::Address bd_addr;
-  ASSERT_TRUE(common::Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
+  Address bd_addr;
+  ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
   uint16_t handle = 0x0001;
   uint16_t num_packets = 100;
-  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::COMPLETE_PDU;
+  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
   BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
   for (uint16_t i = 0; i < num_packets; i++) {
     auto acl_payload = std::make_unique<RawBuilder>();
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
index 461f2a1..4fac6c6 100644
--- a/gd/hci/hci_packets.pdl
+++ b/gd/hci/hci_packets.pdl
@@ -1,7 +1,7 @@
 little_endian_packets
 
-custom_field Address : 48 "common/"
-custom_field ClassOfDevice : 24 "common/"
+custom_field Address : 48 "hci/"
+custom_field ClassOfDevice : 24 "hci/"
 
 enum Enable : 8 {
   DISABLED = 0x00,
@@ -9,7 +9,8 @@
 }
 
 // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
-enum GapDataTypes : 8 {
+enum GapDataType : 8 {
+  INVALID = 0x00,
   FLAGS = 0x01,
   INCOMPLETE_LIST_16_BIT_UUIDS = 0x02,
   COMPLETE_LIST_16_BIT_UUIDS = 0x03,
@@ -23,13 +24,18 @@
   CLASS_OF_DEVICE = 0x0D,
 }
 
+struct GapData {
+  _size_(data) : 8, // Including one byte for data_type
+  data_type : GapDataType,
+  data : 8[+1*8],
+}
+
 // HCI ACL Packets
 
 enum PacketBoundaryFlag : 2 {
   FIRST_NON_AUTOMATICALLY_FLUSHABLE = 0,
   CONTINUING_FRAGMENT = 1,
   FIRST_AUTOMATICALLY_FLUSHABLE = 2,
-  COMPLETE_PDU = 3,
 }
 
 enum BroadcastFlag : 2 {
@@ -58,8 +64,8 @@
   handle : 12,
   packet_status_flag : PacketStatusFlag,
   _reserved_ : 2, // BroadcastFlag
-  _size_(_payload_) : 8,
-  _payload_,
+  _size_(data) : 8,
+  data : 8[],
 }
 
 // HCI Command Packets
@@ -191,6 +197,7 @@
 
   READ_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C79,
   WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C7A,
+  READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D,
 
   // INFORMATIONAL_PARAMETERS
   READ_LOCAL_VERSION_INFORMATION = 0x1001,
@@ -310,6 +317,224 @@
   CONTROLLER_A2DP_OPCODE = 0xFD5D,
 }
 
+// For mapping Local Supported Commands command
+// Value = Octet * 10 + bit
+enum OpCodeIndex : 16 {
+  INQUIRY = 0,
+  INQUIRY_CANCEL = 1,
+  PERIODIC_INQUIRY_MODE = 2,
+  EXIT_PERIODIC_INQUIRY_MODE = 3,
+  CREATE_CONNECTION = 4,
+  DISCONNECT = 5,
+  CREATE_CONNECTION_CANCEL = 7,
+  ACCEPT_CONNECTION_REQUEST = 10,
+  REJECT_CONNECTION_REQUEST = 11,
+  LINK_KEY_REQUEST_REPLY = 12,
+  LINK_KEY_REQUEST_NEGATIVE_REPLY = 13,
+  PIN_CODE_REQUEST_REPLY = 14,
+  PIN_CODE_REQUEST_NEGATIVE_REPLY = 15,
+  CHANGE_CONNECTION_PACKET_TYPE = 16,
+  AUTHENTICATION_REQUESTED = 17,
+  SET_CONNECTION_ENCRYPTION = 20,
+  CHANGE_CONNECTION_LINK_KEY = 21,
+  MASTER_LINK_KEY = 22,
+  REMOTE_NAME_REQUEST = 23,
+  REMOTE_NAME_REQUEST_CANCEL = 24,
+  READ_REMOTE_SUPPORTED_FEATURES = 25,
+  READ_REMOTE_EXTENDED_FEATURES = 26,
+  READ_REMOTE_VERSION_INFORMATION = 27,
+  READ_CLOCK_OFFSET = 30,
+  READ_LMP_HANDLE = 31,
+  HOLD_MODE = 41,
+  SNIFF_MODE = 42,
+  EXIT_SNIFF_MODE = 43,
+  QOS_SETUP = 46,
+  ROLE_DISCOVERY = 47,
+  SWITCH_ROLE = 50,
+  READ_LINK_POLICY_SETTINGS = 51,
+  WRITE_LINK_POLICY_SETTINGS = 52,
+  READ_DEFAULT_LINK_POLICY_SETTINGS = 53,
+  WRITE_DEFAULT_LINK_POLICY_SETTINGS = 54,
+  FLOW_SPECIFICATION = 55,
+  SET_EVENT_MASK = 56,
+  RESET = 57,
+  SET_EVENT_FILTER = 60,
+  FLUSH = 61,
+  READ_PIN_TYPE = 62,
+  WRITE_PIN_TYPE = 63,
+  READ_STORED_LINK_KEY = 65,
+  WRITE_STORED_LINK_KEY = 66,
+  DELETE_STORED_LINK_KEY = 67,
+  WRITE_LOCAL_NAME = 70,
+  READ_LOCAL_NAME = 71,
+  READ_CONNECTION_ACCEPT_TIMEOUT = 72,
+  WRITE_CONNECTION_ACCEPT_TIMEOUT = 73,
+  READ_PAGE_TIMEOUT = 74,
+  WRITE_PAGE_TIMEOUT = 75,
+  READ_SCAN_ENABLE = 76,
+  WRITE_SCAN_ENABLE = 77,
+  READ_PAGE_SCAN_ACTIVITY = 80,
+  WRITE_PAGE_SCAN_ACTIVITY = 81,
+  READ_INQUIRY_SCAN_ACTIVITY = 82,
+  WRITE_INQUIRY_SCAN_ACTIVITY = 83,
+  READ_AUTHENTICATION_ENABLE = 84,
+  WRITE_AUTHENTICATION_ENABLE = 85,
+  READ_CLASS_OF_DEVICE = 90,
+  WRITE_CLASS_OF_DEVICE = 91,
+  READ_VOICE_SETTING = 92,
+  WRITE_VOICE_SETTING = 93,
+  READ_AUTOMATIC_FLUSH_TIMEOUT = 94,
+  WRITE_AUTOMATIC_FLUSH_TIMEOUT = 95,
+  READ_NUM_BROADCAST_RETRANSMITS = 96,
+  WRITE_NUM_BROADCAST_RETRANSMITS = 97,
+  READ_HOLD_MODE_ACTIVITY = 100,
+  WRITE_HOLD_MODE_ACTIVITY = 101,
+  READ_TRANSMIT_POWER_LEVEL = 102,
+  READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 103,
+  WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 104,
+  SET_CONTROLLER_TO_HOST_FLOW_CONTROL = 105,
+  HOST_BUFFER_SIZE = 106,
+  HOST_NUM_COMPLETED_PACKETS = 107,
+  READ_LINK_SUPERVISION_TIMEOUT = 110,
+  WRITE_LINK_SUPERVISION_TIMEOUT = 111,
+  READ_NUMBER_OF_SUPPORTED_IAC = 112,
+  READ_CURRENT_IAC_LAP = 113,
+  WRITE_CURRENT_IAC_LAP = 114,
+  SET_AFH_HOST_CHANNEL_CLASSIFICATION = 121,
+  READ_INQUIRY_SCAN_TYPE = 124,
+  WRITE_INQUIRY_SCAN_TYPE = 125,
+  READ_INQUIRY_MODE = 126,
+  WRITE_INQUIRY_MODE = 127,
+  READ_PAGE_SCAN_TYPE = 130,
+  WRITE_PAGE_SCAN_TYPE = 131,
+  READ_AFH_CHANNEL_ASSESSMENT_MODE = 132,
+  WRITE_AFH_CHANNEL_ASSESSMENT_MODE = 133,
+  READ_LOCAL_VERSION_INFORMATION = 143,
+  READ_LOCAL_SUPPORTED_FEATURES = 145,
+  READ_LOCAL_EXTENDED_FEATURES = 146,
+  READ_BUFFER_SIZE = 147,
+  READ_BD_ADDR = 151,
+  READ_FAILED_CONTACT_COUNTER = 152,
+  RESET_FAILED_CONTACT_COUNTER = 153,
+  READ_LINK_QUALITY = 154,
+  READ_RSSI = 155,
+  READ_AFH_CHANNEL_MAP = 156,
+  READ_CLOCK = 157,
+  READ_LOOPBACK_MODE = 160,
+  WRITE_LOOPBACK_MODE = 161,
+  ENABLE_DEVICE_UNDER_TEST_MODE = 162,
+  SETUP_SYNCHRONOUS_CONNECTION = 163,
+  ACCEPT_SYNCHRONOUS_CONNECTION = 164,
+  REJECT_SYNCHRONOUS_CONNECTION = 165,
+  READ_EXTENDED_INQUIRY_RESPONSE = 170,
+  WRITE_EXTENDED_INQUIRY_RESPONSE = 171,
+  REFRESH_ENCRYPTION_KEY = 172,
+  SNIFF_SUBRATING = 174,
+  READ_SIMPLE_PAIRING_MODE = 175,
+  WRITE_SIMPLE_PAIRING_MODE = 176,
+  READ_LOCAL_OOB_DATA = 177,
+  READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = 180,
+  WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = 181,
+  IO_CAPABILITY_REQUEST_REPLY = 187,
+  USER_CONFIRMATION_REQUEST_REPLY = 190,
+  USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = 191,
+  USER_PASSKEY_REQUEST_REPLY = 192,
+  USER_PASSKEY_REQUEST_NEGATIVE_REPLY = 193,
+  REMOTE_OOB_DATA_REQUEST_REPLY = 194,
+  WRITE_SIMPLE_PAIRING_DEBUG_MODE = 195,
+  REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = 197,
+  SEND_KEYPRESS_NOTIFICATION = 202,
+  IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 203,
+  READ_ENCRYPTION_KEY_SIZE = 204,
+  READ_DATA_BLOCK_SIZE = 232,
+  READ_LE_HOST_SUPPORT = 245,
+  WRITE_LE_HOST_SUPPORT = 246,
+  LE_SET_EVENT_MASK = 250,
+  LE_READ_BUFFER_SIZE = 251,
+  LE_READ_LOCAL_SUPPORTED_FEATURES = 252,
+  LE_SET_RANDOM_ADDRESS = 254,
+  LE_SET_ADVERTISING_PARAMETERS = 255,
+  LE_READ_ADVERTISING_CHANNEL_TX_POWER = 256,
+  LE_SET_ADVERTISING_DATA = 257,
+  LE_SET_SCAN_RESPONSE_DATA = 260,
+  LE_SET_ADVERTISING_ENABLE = 261,
+  LE_SET_SCAN_PARAMETERS = 262,
+  LE_SET_SCAN_ENABLE = 263,
+  LE_CREATE_CONNECTION = 264,
+  LE_CREATE_CONNECTION_CANCEL = 265,
+  LE_READ_WHITE_LIST_SIZE = 266,
+  LE_CLEAR_WHITE_LIST = 267,
+  LE_ADD_DEVICE_TO_WHITE_LIST = 270,
+  LE_REMOVE_DEVICE_FROM_WHITE_LIST = 271,
+  LE_CONNECTION_UPDATE = 272,
+  LE_SET_HOST_CHANNEL_CLASSIFICATION = 273,
+  LE_READ_CHANNEL_MAP = 274,
+  LE_READ_REMOTE_FEATURES = 275,
+  LE_ENCRYPT = 276,
+  LE_RAND = 277,
+  LE_START_ENCRYPTION = 280,
+  LE_LONG_TERM_KEY_REQUEST_REPLY = 281,
+  LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = 282,
+  LE_READ_SUPPORTED_STATES = 283,
+  LE_RECEIVER_TEST = 284,
+  LE_TRANSMITTER_TEST = 285,
+  LE_TEST_END = 286,
+  ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = 293,
+  ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = 294,
+  READ_LOCAL_SUPPORTED_CODECS = 295,
+  READ_SECURE_CONNECTIONS_HOST_SUPPORT = 322,
+  WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = 323,
+  READ_LOCAL_OOB_EXTENDED_DATA = 326,
+  WRITE_SECURE_CONNECTIONS_TEST_MODE = 327,
+  LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = 334,
+  LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = 335,
+  LE_SET_DATA_LENGTH = 336,
+  LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = 337,
+  LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = 340,
+  LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = 341,
+  LE_GENERATE_DHKEY_COMMAND = 342,
+  LE_ADD_DEVICE_TO_RESOLVING_LIST = 343,
+  LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = 344,
+  LE_CLEAR_RESOLVING_LIST = 345,
+  LE_READ_RESOLVING_LIST_SIZE = 346,
+  LE_READ_PEER_RESOLVABLE_ADDRESS = 347,
+  LE_READ_LOCAL_RESOLVABLE_ADDRESS = 350,
+  LE_SET_ADDRESS_RESOLUTION_ENABLE = 351,
+  LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = 352,
+  LE_READ_MAXIMUM_DATA_LENGTH = 353,
+  LE_READ_PHY = 354,
+  LE_SET_DEFAULT_PHY = 355,
+  LE_SET_PHY = 356,
+  LE_ENHANCED_RECEIVER_TEST = 357,
+  LE_ENHANCED_TRANSMITTER_TEST = 360,
+  LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = 361,
+  LE_SET_EXTENDED_ADVERTISING_PARAMETERS = 362,
+  LE_SET_EXTENDED_ADVERTISING_DATA = 363,
+  LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = 364,
+  LE_SET_EXTENDED_ADVERTISING_ENABLE = 365,
+  LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 366,
+  LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 367,
+  LE_REMOVE_ADVERTISING_SET = 370,
+  LE_CLEAR_ADVERTISING_SETS = 371,
+  LE_SET_PERIODIC_ADVERTISING_PARAM = 372,
+  LE_SET_PERIODIC_ADVERTISING_DATA = 373,
+  LE_SET_PERIODIC_ADVERTISING_ENABLE = 374,
+  LE_SET_EXTENDED_SCAN_PARAMETERS = 375,
+  LE_SET_EXTENDED_SCAN_ENABLE = 376,
+  LE_EXTENDED_CREATE_CONNECTION = 377,
+  LE_PERIODIC_ADVERTISING_CREATE_SYNC = 380,
+  LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 381,
+  LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 382,
+  LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 383,
+  LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 384,
+  LE_CLEAR_PERIODIC_ADVERTISING_LIST = 385,
+  LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 386,
+  LE_READ_TRANSMIT_POWER = 387,
+  LE_READ_RF_PATH_COMPENSATION_POWER = 390,
+  LE_WRITE_RF_PATH_COMPENSATION_POWER = 391,
+  LE_SET_PRIVACY_MODE = 392,
+}
+
 packet CommandPacket {
   op_code : OpCode,
   _size_(_payload_) : 8,
@@ -323,6 +548,7 @@
 packet SecurityCommand : CommandPacket { _payload_, }
 packet ScoConnectionCommand : CommandPacket { _payload_, }
 packet LeAdvertisingCommand : CommandPacket { _payload_, }
+packet LeScanningCommand : CommandPacket { _payload_, }
 packet LeConnectionManagementCommand : CommandPacket { _payload_, }
 packet LeSecurityCommand : CommandPacket { _payload_, }
 packet VendorCommand : CommandPacket { _payload_, }
@@ -358,7 +584,7 @@
   DATA_BUFFER_OVERFLOW = 0x1A,
   MAX_SLOTS_CHANGE = 0x1B,
   READ_CLOCK_OFFSET_COMPLETE = 0x1C,
-  CONNECTION_PACKET_TYPE_CHANGE = 0x1D,
+  CONNECTION_PACKET_TYPE_CHANGED = 0x1D,
   QOS_VIOLATION = 0x1E,
   PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
   FLOW_SPECIFICATION_COMPLETE = 0x21,
@@ -457,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
@@ -478,10 +706,15 @@
 packet NoCommandComplete : CommandComplete (command_op_code = NONE){
 }
 
+struct Lap { // Lower Address Part
+  lap : 6,
+  _reserved_ : 2,
+  _fixed_ = 0x9e8b : 16,
+}
+
   // LINK_CONTROL
 packet Inquiry : DiscoveryCommand (op_code = INQUIRY) {
-  lap0 : 8, // 0x00 - 0x3F
-  _fixed_ = 0x9E8B : 16, // LAP upper bits are _fixed_
+  lap : Lap,
   inquiry_length : 8, // 0x1 - 0x30 (times 1.28s)
   num_responses : 8, // 0x00 unlimited
 }
@@ -497,7 +730,11 @@
 }
 
 packet PeriodicInquiryMode : DiscoveryCommand (op_code = PERIODIC_INQUIRY_MODE) {
-  _payload_,  // placeholder (unimplemented)
+  max_period_length : 16, // Range 0x0003 to 0xffff (times 1.28s)
+  min_period_length : 16, // Range 0x0002 to 0xfffe (times 1.28s)
+  lap : Lap,
+  inquiry_length : 8, // 0x1 - 0x30 (times 1.28s)
+  num_responses : 8, // 0x00 unlimited
 }
 
 packet PeriodicInquiryModeComplete : CommandComplete (command_op_code = PERIODIC_INQUIRY_MODE) {
@@ -597,8 +834,7 @@
 
 packet LinkKeyRequestReply : SecurityCommand (op_code = LINK_KEY_REQUEST_REPLY) {
   bd_addr : Address,
-  link_key_lo : 64,
-  link_key_hi : 64,
+  link_key : 8[16],
 }
 
 packet LinkKeyRequestReplyComplete : CommandComplete (command_op_code = LINK_KEY_REQUEST_REPLY) {
@@ -618,21 +854,7 @@
   bd_addr : Address,
   pin_code_length : 5, // 0x01 - 0x10
   _reserved_ : 3,
-  pin_code_1 : 8, // string parameter, first octet first
-  pin_code_2 : 8,
-  pin_code_3 : 8,
-  pin_code_4 : 8,
-  pin_code_5 : 8,
-  pin_code_6 : 8,
-  pin_code_7 : 8,
-  pin_code_8 : 8,
-  pin_code_9 : 8,
-  pin_code_10 : 8,
-  pin_code_11 : 8,
-  pin_code_12 : 8,
-  pin_code_13 : 8,
-  pin_code_14 : 8,
-  pin_code_15 : 8,
+  pin_code : 8[16], // string parameter, first octet first
 }
 
 packet PinCodeRequestReplyComplete : CommandComplete (command_op_code = PIN_CODE_REQUEST_REPLY) {
@@ -831,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,
 }
@@ -846,7 +1068,9 @@
 }
 
 packet RemoteOobDataRequestReply : SecurityCommand (op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
-  _payload_,  // placeholder (unimplemented)
+  bd_addr : Address,
+  c : 8[16],
+  r : 8[16],
 }
 
 packet RemoteOobDataRequestReplyComplete : CommandComplete (command_op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
@@ -884,53 +1108,163 @@
 
   // LINK_POLICY
 packet HoldMode : ConnectionManagementCommand (op_code = HOLD_MODE) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  hold_mode_max_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+  hold_mode_min_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
 }
 
+packet HoldModeStatus : CommandStatus (command_op_code = HOLD_MODE) {
+}
+
+
 packet SniffMode : ConnectionManagementCommand (op_code = SNIFF_MODE) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  sniff_max_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+  sniff_min_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+  sniff_attempt: 16, // 0x0001-0x7FFF (1.25ms-40.9s)
+  sniff_timeout: 16, // 0x0000-0x7FFF (0ms-40.9s)
 }
 
+packet SniffModeStatus : CommandStatus (command_op_code = SNIFF_MODE) {
+}
+
+
 packet ExitSniffMode : ConnectionManagementCommand (op_code = EXIT_SNIFF_MODE) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+packet ExitSniffModeStatus : CommandStatus (command_op_code = EXIT_SNIFF_MODE) {
+}
+
+enum ServiceType : 8 {
+  NO_TRAFFIC = 0x00,
+  BEST_EFFORT = 0x01,
+  GUARANTEED = 0x02,
 }
 
 packet QosSetup : ConnectionManagementCommand (op_code = QOS_SETUP) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  _reserved_ : 8,
+  service_type : ServiceType,
+  token_rate : 32, // Octets/s
+  peak_bandwidth : 32, // Octets/s
+  latency : 32, // Octets/s
+  delay_variation : 32, // microseconds
+}
+
+packet QosSetupStatus : CommandStatus (command_op_code = QOS_SETUP) {
 }
 
 packet RoleDiscovery : ConnectionManagementCommand (op_code = ROLE_DISCOVERY) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+enum Role : 8 {
+  MASTER = 0x00,
+  SLAVE = 0x01,
+}
+
+packet RoleDiscoveryComplete : CommandComplete (command_op_code = ROLE_DISCOVERY) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  current_role : Role,
 }
 
 packet SwitchRole : ConnectionManagementCommand (op_code = SWITCH_ROLE) {
-  _payload_,  // placeholder (unimplemented)
+  bd_addr : Address,
+  role : Role,
 }
 
+packet SwitchRoleStatus : CommandStatus (command_op_code = SWITCH_ROLE) {
+}
+
+
 packet ReadLinkPolicySettings : ConnectionManagementCommand (op_code = READ_LINK_POLICY_SETTINGS) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+enum LinkPolicy : 16 {
+  ENABLE_ROLE_SWITCH = 0x01,
+  ENABLE_HOLD_MODE = 0x02,
+  ENABLE_SNIFF_MODE = 0x04,
+  ENABLE_PARK_MODE = 0x08, // deprecated after 5.0
+}
+
+packet ReadLinkPolicySettingsComplete : CommandComplete (command_op_code = READ_LINK_POLICY_SETTINGS) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  link_policy_settings : 16,
 }
 
 packet WriteLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_LINK_POLICY_SETTINGS) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  link_policy_settings : 16,
+}
+
+packet WriteLinkPolicySettingsComplete : CommandComplete (command_op_code = WRITE_LINK_POLICY_SETTINGS) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
 }
 
 packet ReadDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = READ_DEFAULT_LINK_POLICY_SETTINGS) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet ReadDefaultLinkPolicySettingsComplete : CommandComplete (command_op_code = READ_DEFAULT_LINK_POLICY_SETTINGS) {
+  status : ErrorCode,
+  default_link_policy_settings : 16,
 }
 
 packet WriteDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_DEFAULT_LINK_POLICY_SETTINGS) {
-  _payload_,  // placeholder (unimplemented)
+  default_link_policy_settings : 16,
+}
+
+packet WriteDefaultLinkPolicySettingsComplete : CommandComplete (command_op_code = WRITE_DEFAULT_LINK_POLICY_SETTINGS) {
+  status : ErrorCode,
+}
+
+enum FlowDirection : 8 {
+  OUTGOING_FLOW = 0x00,
+  INCOMING_FLOW = 0x01,
 }
 
 packet FlowSpecification : ConnectionManagementCommand (op_code = FLOW_SPECIFICATION) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  _reserved_ : 8,
+  flow_direction : FlowDirection,
+  service_type : ServiceType,
+  token_rate : 32, // Octets/s
+  token_bucket_size : 32,
+  peak_bandwidth : 32, // Octets/s
+  access_latency : 32, // Octets/s
+}
+
+packet FlowSpecificationStatus : CommandStatus (command_op_code = FLOW_SPECIFICATION) {
 }
 
 packet SniffSubrating : ConnectionManagementCommand (op_code = SNIFF_SUBRATING) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  maximum_latency : 16,  // 0x0002-0xFFFE (1.25ms-40.9s)
+  minimum_remote_timeout : 16, // 0x0000-0xFFFE (0-40.9s)
+  minimum_local_timeout: 16, // 0x0000-0xFFFE (0-40.9s)
 }
 
+packet SniffSubratingComplete : CommandComplete (command_op_code = SNIFF_SUBRATING) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+}
 
   // CONTROLLER_AND_BASEBAND
 packet SetEventMask : CommandPacket (op_code = SET_EVENT_MASK) {
@@ -948,12 +1282,82 @@
   status : ErrorCode,
 }
 
+enum FilterType : 8 {
+  CLEAR_ALL_FILTERS = 0x00,
+  INQUIRY_RESULT = 0x01,
+  CONNECTION_SETUP = 0x02,
+}
+
 packet SetEventFilter : CommandPacket (op_code = SET_EVENT_FILTER) {
-  _payload_,  // placeholder (unimplemented)
+  filter_type : FilterType,
+  _body_,
+}
+
+packet SetEventFilterComplete : CommandComplete (command_op_code = SET_EVENT_FILTER) {
+  status : ErrorCode,
+}
+
+packet SetEventFilterClearAll : SetEventFilter (filter_type = CLEAR_ALL_FILTERS) {
+}
+
+enum FilterConditionType : 8 {
+  ALL_DEVICES = 0x00,
+  CLASS_OF_DEVICE = 0x01,
+  ADDRESS = 0x02,
+}
+
+packet SetEventFilterInquiryResult : SetEventFilter (filter_type = INQUIRY_RESULT) {
+  filter_condition_type : FilterConditionType,
+  _body_,
+}
+
+packet SetEventFilterInquiryResultAllDevices : SetEventFilterInquiryResult (filter_condition_type = ALL_DEVICES) {
+}
+
+packet SetEventFilterInquiryResultClassOfDevice : SetEventFilterInquiryResult (filter_condition_type = CLASS_OF_DEVICE) {
+  class_of_device : ClassOfDevice,
+  class_of_device_mask : ClassOfDevice,
+}
+
+packet SetEventFilterInquiryResultAddress : SetEventFilterInquiryResult (filter_condition_type = ADDRESS) {
+  address : Address,
+}
+
+packet SetEventFilterConnectionSetup : SetEventFilter (filter_type = CONNECTION_SETUP) {
+  filter_condition_type : FilterConditionType,
+  _body_,
+}
+
+enum AutoAcceptFlag : 8 {
+  AUTO_ACCEPT_OFF = 0x01,
+  AUTO_ACCEPT_ON_ROLE_SWITCH_DISABLED = 0x02,
+  AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED = 0x03,
+}
+
+packet SetEventFilterConnectionSetupAllDevices : SetEventFilterConnectionSetup (filter_condition_type = ALL_DEVICES) {
+  auto_accept_flag : AutoAcceptFlag,
+}
+
+packet SetEventFilterConnectionSetupClassOfDevice : SetEventFilterConnectionSetup (filter_condition_type = CLASS_OF_DEVICE) {
+  class_of_device : ClassOfDevice,
+  class_of_device_mask : ClassOfDevice,
+  auto_accept_flag : AutoAcceptFlag,
+}
+
+packet SetEventFilterConnectionSetupAddress : SetEventFilterConnectionSetup (filter_condition_type = ADDRESS) {
+  address : Address,
+  auto_accept_flag : AutoAcceptFlag,
 }
 
 packet Flush : ConnectionManagementCommand (op_code = FLUSH) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+packet FlushComplete : CommandComplete (command_op_code = FLUSH) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
 }
 
 packet ReadPinType : CommandPacket (op_code = READ_PIN_TYPE) {
@@ -984,8 +1388,14 @@
   num_keys_read : 16,
 }
 
+struct KeyAndAddress {
+  address : Address,
+  link_key : 8[16],
+}
+
 packet WriteStoredLinkKey : SecurityCommand (op_code = WRITE_STORED_LINK_KEY) {
-  _payload_,
+  _count_(keys_to_write) : 8, // 0x01-0x0B
+  keys_to_write : KeyAndAddress[],
 }
 
 packet WriteStoredLinkKeyComplete : CommandComplete (command_op_code = WRITE_STORED_LINK_KEY) {
@@ -1005,11 +1415,11 @@
 
 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) {
-  _payload_,
+  local_name : 8[248], // Null-terminated UTF-8 encoded name
 }
 
 packet WriteLocalNameComplete : CommandComplete (command_op_code = WRITE_LOCAL_NAME) {
@@ -1021,7 +1431,7 @@
 
 packet ReadLocalNameComplete : CommandComplete (command_op_code = READ_LOCAL_NAME) {
   status : ErrorCode,
-  _payload_,
+  local_name : 8[248], // Null-terminated UTF-8 encoded name
 }
 
 packet ReadConnectionAcceptTimeout : ConnectionManagementCommand (op_code = READ_CONNECTION_ACCEPT_TIMEOUT) {
@@ -1033,11 +1443,19 @@
 }
 
 packet ReadPageTimeout : DiscoveryCommand (op_code = READ_PAGE_TIMEOUT) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet ReadPageTimeoutComplete : CommandComplete (command_op_code = READ_PAGE_TIMEOUT) {
+  status : ErrorCode,
+  page_timeout : 16,
 }
 
 packet WritePageTimeout : DiscoveryCommand (op_code = WRITE_PAGE_TIMEOUT) {
-  _payload_,  // placeholder (unimplemented)
+  page_timeout : 16,
+}
+
+packet WritePageTimeoutComplete : CommandComplete (command_op_code = WRITE_PAGE_TIMEOUT) {
+  status : ErrorCode,
 }
 
 enum ScanEnable : 8 {
@@ -1082,11 +1500,21 @@
 }
 
 packet ReadInquiryScanActivity : DiscoveryCommand (op_code = READ_INQUIRY_SCAN_ACTIVITY) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet ReadInquiryScanActivityComplete : CommandComplete (command_op_code = READ_INQUIRY_SCAN_ACTIVITY) {
+  status : ErrorCode,
+  inquiry_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+  inquiry_scan_window : 16, // Range: 0x0011 to 0x1000
 }
 
 packet WriteInquiryScanActivity : DiscoveryCommand (op_code = WRITE_INQUIRY_SCAN_ACTIVITY) {
-  _payload_,  // placeholder (unimplemented)
+  inquiry_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+  inquiry_scan_window : 16, // Range: 0x0011 to 0x1000
+}
+
+packet WriteInquiryScanActivityComplete : CommandComplete (command_op_code = WRITE_INQUIRY_SCAN_ACTIVITY) {
+  status : ErrorCode,
 }
 
 enum AuthenticationEnable : 8 {
@@ -1102,7 +1530,7 @@
   authentication_enable : AuthenticationEnable,
 }
 
-packet WriteAuthenticationEnable : CommandPacket (op_code = WRITE_AUTHENTICATION_ENABLE) {
+packet WriteAuthenticationEnable : SecurityCommand (op_code = WRITE_AUTHENTICATION_ENABLE) {
   authentication_enable : AuthenticationEnable,
 }
 
@@ -1134,12 +1562,32 @@
   _payload_,  // placeholder (unimplemented)
 }
 
+packet WriteVoiceSettingComplete : CommandComplete (command_op_code = WRITE_VOICE_SETTING) {
+  status : ErrorCode,
+}
+
 packet ReadAutomaticFlushTimeout : ConnectionManagementCommand (op_code = READ_AUTOMATIC_FLUSH_TIMEOUT) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+packet ReadAutomaticFlushTimeoutComplete : CommandComplete (command_op_code = READ_AUTOMATIC_FLUSH_TIMEOUT) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  flush_timeout : 16,
 }
 
 packet WriteAutomaticFlushTimeout : ConnectionManagementCommand (op_code = WRITE_AUTOMATIC_FLUSH_TIMEOUT) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  flush_timeout : 16, // 0x0000-0x07FF Default 0x0000 (No Automatic Flush)
+}
+
+packet WriteAutomaticFlushTimeoutComplete : CommandComplete (command_op_code = WRITE_AUTOMATIC_FLUSH_TIMEOUT) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
 }
 
 packet ReadNumBroadcastRetransmits : CommandPacket (op_code = READ_NUM_BROADCAST_RETRANSMITS) {
@@ -1158,8 +1606,24 @@
   _payload_,  // placeholder (unimplemented)
 }
 
+
+enum TransmitPowerLevelType : 8 {
+  CURRENT = 0x00,
+  MAXIMUM = 0x01,
+}
+
 packet ReadTransmitPowerLevel : ConnectionManagementCommand (op_code = READ_TRANSMIT_POWER_LEVEL) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle : 12,
+  _reserved_ : 4,
+  type : TransmitPowerLevelType,
+
+}
+
+packet ReadTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_TRANSMIT_POWER_LEVEL) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  transmit_power_level : 8,
 }
 
 packet ReadSynchronousFlowControlEnable : CommandPacket (op_code = READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE) {
@@ -1185,8 +1649,15 @@
   status : ErrorCode,
 }
 
+struct CompletedPackets {
+  connection_handle : 12,
+  _reserved_ : 4,
+  host_num_of_completed_packets : 16,
+}
+
 packet HostNumCompletedPackets : CommandPacket (op_code = HOST_NUM_COMPLETED_PACKETS) {
-  _payload_,
+  _count_(completed_packets) : 8,
+  completed_packets : CompletedPackets[],
 }
 
 packet HostNumCompletedPacketsError : CommandComplete (command_op_code = HOST_NUM_COMPLETED_PACKETS) {
@@ -1200,7 +1671,7 @@
 
 packet ReadLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = READ_LINK_SUPERVISION_TIMEOUT) {
   status : ErrorCode,
-  handle : 12,
+  connection_handle : 12,
   _reserved_ : 4,
   link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
 }
@@ -1213,20 +1684,34 @@
 
 packet WriteLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = WRITE_LINK_SUPERVISION_TIMEOUT) {
   status : ErrorCode,
-  handle : 12,
+  connection_handle : 12,
   _reserved_ : 4,
 }
 
 packet ReadNumberOfSupportedIac : DiscoveryCommand (op_code = READ_NUMBER_OF_SUPPORTED_IAC) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet ReadNumberOfSupportedIacComplete : CommandComplete (command_op_code = READ_NUMBER_OF_SUPPORTED_IAC) {
+  status : ErrorCode,
+  num_support_iac : 8,
 }
 
 packet ReadCurrentIacLap : DiscoveryCommand (op_code = READ_CURRENT_IAC_LAP) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet ReadCurrentIacLapComplete : CommandComplete (command_op_code = READ_CURRENT_IAC_LAP) {
+  status : ErrorCode,
+  _count_(laps_to_read) : 8,
+  laps_to_read : Lap[],
 }
 
 packet WriteCurrentIacLap : DiscoveryCommand (op_code = WRITE_CURRENT_IAC_LAP) {
-  _payload_,  // placeholder (unimplemented)
+  _count_(laps_to_write) : 8,
+  laps_to_write : Lap[],
+}
+
+packet WriteCurrentIacLapComplete : CommandComplete (command_op_code = WRITE_CURRENT_IAC_LAP) {
+  status : ErrorCode,
 }
 
 packet SetAfhHostChannelClassification : CommandPacket (op_code = SET_AFH_HOST_CHANNEL_CLASSIFICATION) {
@@ -1316,12 +1801,13 @@
 packet ReadExtendedInquiryResponseComplete : CommandComplete (command_op_code = READ_EXTENDED_INQUIRY_RESPONSE) {
   status : ErrorCode,
   fec_required : FecRequired,
-  _payload_,
+  extended_inquiry_response : GapData[],
 }
 
 packet WriteExtendedInquiryResponse : CommandPacket (op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
   fec_required : FecRequired,
-  _payload_,
+  extended_inquiry_response : GapData[],
+  _padding_[244], // Zero padding to be 240 octets (GapData[]) + 2 (opcode) + 1 (size) + 1 (FecRequired)
 }
 
 packet WriteExtendedInquiryResponseComplete : CommandComplete (command_op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
@@ -1357,10 +1843,8 @@
 
 packet ReadLocalOobDataComplete : CommandComplete (command_op_code = READ_LOCAL_OOB_DATA) {
   status : ErrorCode,
-  clo : 64,
-  chi : 64,
-  rlo : 64,
-  rhi : 64,
+  c : 8[16],
+  r : 8[16],
 }
 
 packet ReadInquiryResponseTransmitPowerLevel : DiscoveryCommand (op_code = READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL) {
@@ -1427,7 +1911,7 @@
   secure_connections_host_support : Enable,
 }
 
-packet WriteSecureConnectionsHostSupport : CommandPacket (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+packet WriteSecureConnectionsHostSupport : SecurityCommand (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
   secure_connections_host_support : Enable,
 }
 
@@ -1435,12 +1919,24 @@
   status : ErrorCode,
 }
 
+packet ReadLocalOobExtendedData : SecurityCommand (op_code = READ_LOCAL_OOB_EXTENDED_DATA) {
+}
+
+packet ReadLocalOobExtendedDataComplete : CommandComplete (command_op_code = READ_LOCAL_OOB_EXTENDED_DATA) {
+  status : ErrorCode,
+  c_192 : 8[16],
+  r_192 : 8[16],
+  c_256 : 8[16],
+  r_256 : 8[16],
+}
+
+
   // INFORMATIONAL_PARAMETERS
 packet ReadLocalVersionInformation : CommandPacket (op_code = READ_LOCAL_VERSION_INFORMATION) {
 }
 
 enum HciVersion : 8 {
-  V_1_0b = 0x00,
+  V_1_0B = 0x00,
   V_1_1 = 0x01,
   V_1_2 = 0x02,
   V_2_0 = 0x03, //  + EDR
@@ -1454,7 +1950,7 @@
 }
 
 enum LmpVersion : 8 {
-  V_1_0b = 0x00, // withdrawn
+  V_1_0B = 0x00, // withdrawn
   V_1_1 = 0x01, // withdrawn
   V_1_2 = 0x02, // withdrawn
   V_2_0 = 0x03, //  + EDR
@@ -1467,8 +1963,7 @@
   V_5_1 = 0x0a,
 }
 
-packet ReadLocalVersionInformationComplete : CommandComplete (command_op_code = READ_LOCAL_VERSION_INFORMATION) {
-  status : ErrorCode,
+struct LocalVersionInformation {
   hci_version : HciVersion,
   hci_revision : 16,
   lmp_version : LmpVersion,
@@ -1476,6 +1971,11 @@
   lmp_subversion : 16,
 }
 
+packet ReadLocalVersionInformationComplete : CommandComplete (command_op_code = READ_LOCAL_VERSION_INFORMATION) {
+  status : ErrorCode,
+  local_version_information : LocalVersionInformation,
+}
+
 packet ReadLocalSupportedCommands : CommandPacket (op_code = READ_LOCAL_SUPPORTED_COMMANDS) {
 }
 
@@ -1496,6 +1996,13 @@
   page_number : 8,
 }
 
+packet ReadLocalExtendedFeaturesComplete : CommandComplete (command_op_code = READ_LOCAL_EXTENDED_FEATURES) {
+  status : ErrorCode,
+  page_number : 8,
+  maximum_page_number : 8,
+  extended_lmp_features : 64,
+}
+
 packet ReadBufferSize : CommandPacket (op_code = READ_BUFFER_SIZE) {
 }
 
@@ -1521,26 +2028,60 @@
 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) {
-  handle : 12,
+  connection_handle : 12,
   _reserved_ : 4,
 }
 
+packet ReadFailedContactCounterComplete : CommandComplete (command_op_code = READ_FAILED_CONTACT_COUNTER) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  failed_contact_counter : 16,
+}
+
 packet ResetFailedContactCounter : ConnectionManagementCommand (op_code = RESET_FAILED_CONTACT_COUNTER) {
-  handle : 12,
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+packet ResetFailedContactCounterComplete : CommandComplete (command_op_code = RESET_FAILED_CONTACT_COUNTER) {
+  status : ErrorCode,
+  connection_handle : 12,
   _reserved_ : 4,
 }
 
 packet ReadLinkQuality : ConnectionManagementCommand (op_code = READ_LINK_QUALITY) {
-  handle : 12,
+  connection_handle : 12,
   _reserved_ : 4,
 }
 
-packet ReadRssi : ConnectionManagementCommand (op_code = READ_RSSI) {
-  handle : 12,
+packet ReadLinkQualityComplete : CommandComplete (command_op_code = READ_LINK_QUALITY) {
+  status : ErrorCode,
+  connection_handle : 12,
   _reserved_ : 4,
+  link_quality : 8,
+}
+
+packet ReadRssi : ConnectionManagementCommand (op_code = READ_RSSI) {
+  connection_handle : 12,
+  _reserved_ : 4,
+}
+
+packet ReadRssiComplete : CommandComplete (command_op_code = READ_RSSI) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  rssi : 8,
 }
 
 packet ReadAfhChannelMap : ConnectionManagementCommand (op_code = READ_AFH_CHANNEL_MAP) {
@@ -1548,6 +2089,20 @@
   _reserved_ : 4,
 }
 
+enum AfhMode : 8 {
+  AFH_DISABLED = 0x00,
+  AFH_ENABLED = 0x01,
+}
+
+packet ReadAfhChannelMapComplete : CommandComplete (command_op_code = READ_AFH_CHANNEL_MAP) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  afh_mode : AfhMode,
+  afh_channel_map : 8[10],
+}
+
+
 enum WhichClock : 8 {
   LOCAL = 0x00,
   PICONET = 0x01,
@@ -1559,11 +2114,26 @@
   which_clock : WhichClock,
 }
 
+packet ReadClockComplete : CommandComplete (command_op_code = READ_CLOCK) {
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  clock : 28,
+  _reserved_ : 4,
+  accuracy : 16,
+}
+
 packet ReadEncryptionKeySize : SecurityCommand (op_code = READ_ENCRYPTION_KEY_SIZE) {
   connection_handle : 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 {
@@ -1626,10 +2196,14 @@
 packet LeReadBufferSize : CommandPacket (op_code = LE_READ_BUFFER_SIZE) {
 }
 
+struct LeBufferSize {
+  le_data_packet_length : 16,
+  total_num_le_packets : 8,
+}
+
 packet LeReadBufferSizeComplete : CommandComplete (command_op_code = LE_READ_BUFFER_SIZE) {
   status : ErrorCode,
-  hc_le_data_packet_length : 16,
-  hc_total_num_le_packets : 8,
+  le_buffer_size : LeBufferSize,
 }
 
 packet LeReadLocalSupportedFeatures : CommandPacket (op_code = LE_READ_LOCAL_SUPPORTED_FEATURES) {
@@ -1640,7 +2214,7 @@
   le_features : 64,
 }
 
-packet LeSetRandomAddress : CommandPacket (op_code = LE_SET_RANDOM_ADDRESS) {
+packet LeSetRandomAddress : LeAdvertisingCommand (op_code = LE_SET_RANDOM_ADDRESS) {
   random_address : Address,
 }
 
@@ -1648,9 +2222,11 @@
   status : ErrorCode,
 }
 
-enum AdvertisingFilterPolicy : 1 {
+enum AdvertisingFilterPolicy : 2 {
   ALL_DEVICES = 0, // Default
-  ONLY_WHITE_LISTED_DEVICES = 1,
+  WHITELISTED_SCAN = 1,
+  WHITELISTED_CONNECT = 2,
+  WHITELISTED_SCAN_AND_CONNECT = 3,
 }
 
 enum PeerAddressType : 8 {
@@ -1663,7 +2239,7 @@
   ADV_DIRECT_IND = 0x01,
   ADV_SCAN_IND = 0x02,
   ADV_NONCONN_IND = 0x03,
-  SCAN_RSP = 0x04,
+  ADV_DIRECT_IND_LOW = 0x04,
 }
 
 enum AddressType : 8 {
@@ -1674,15 +2250,14 @@
 }
 
 packet LeSetAdvertisingParameters : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_PARAMETERS) {
-  advertising_interval_min : 16,
-  advertising_interval_max : 16,
-  advertising_type : AdvertisingEventType,
+  interval_min : 16,
+  interval_max : 16,
+  type : AdvertisingEventType,
   own_address_type : AddressType,
   peer_address_type : PeerAddressType,
   peer_address : Address,
-  advertising_channel_map : 8,
-  connection_filter_policy : AdvertisingFilterPolicy,
-  scan_filter_policy : AdvertisingFilterPolicy,
+  channel_map : 8,
+  filter_policy : AdvertisingFilterPolicy,
   _reserved_ : 6,
 }
 
@@ -1699,7 +2274,9 @@
 }
 
 packet LeSetAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_DATA) {
-  _payload_,
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+  _padding_[31], // Zero padding to 31 bytes of advertising_data
 }
 
 packet LeSetAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_DATA) {
@@ -1707,7 +2284,9 @@
 }
 
 packet LeSetScanResponseData : LeAdvertisingCommand (op_code = LE_SET_SCAN_RESPONSE_DATA) {
-  _payload_,
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+  _padding_[31], // Zero padding to 31 bytes of advertising_data
 }
 
 packet LeSetScanResponseDataComplete : CommandComplete (command_op_code = LE_SET_SCAN_RESPONSE_DATA) {
@@ -1734,7 +2313,7 @@
   WHITE_LIST_AND_INITIATORS_IDENTITY = 0x03,
 }
 
-packet LeSetScanParameters : LeAdvertisingCommand (op_code = LE_SET_SCAN_PARAMETERS) {
+packet LeSetScanParameters : LeScanningCommand (op_code = LE_SET_SCAN_PARAMETERS) {
   le_scan_type : LeScanType,
   le_scan_interval : 16, // 0x0004-0x4000 Default 0x10 (10ms)
   le_scan_window : 16, // Default 0x10 (10ms)
@@ -1746,7 +2325,7 @@
   status : ErrorCode,
 }
 
-packet LeSetScanEnable : LeAdvertisingCommand (op_code = LE_SET_SCAN_ENABLE) {
+packet LeSetScanEnable : LeScanningCommand (op_code = LE_SET_SCAN_ENABLE) {
   le_scan_enable : Enable,
   filter_duplicates : Enable,
 }
@@ -1788,6 +2367,9 @@
 packet LeCreateConnectionCancel : LeConnectionManagementCommand (op_code = LE_CREATE_CONNECTION_CANCEL) {
 }
 
+packet LeCreateConnectionCancelStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION_CANCEL) {
+}
+
 packet LeCreateConnectionCancelComplete : CommandComplete (command_op_code = LE_CREATE_CONNECTION_CANCEL) {
   status : ErrorCode,
 }
@@ -1862,15 +2444,26 @@
 }
 
 packet LeRand : LeSecurityCommand (op_code = LE_RAND) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet LeRandComplete : CommandComplete (command_op_code = LE_RAND) {
+  status : ErrorCode,
+  random_number : 64,
 }
 
 packet LeStartEncryption : LeSecurityCommand (op_code = LE_START_ENCRYPTION) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle: 16,
+  rand: 8[8],
+  ediv: 16,
+  ltk: 8[16],
+}
+
+packet LeStartEncryptionStatus : CommandStatus (command_op_code = LE_START_ENCRYPTION) {
 }
 
 packet LeLongTermKeyRequestReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_REPLY) {
-  _payload_,  // placeholder (unimplemented)
+  connection_handle: 16,
+  long_term_key: 8[16],
 }
 
 packet LeLongTermKeyRequestNegativeReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY) {
@@ -1878,7 +2471,11 @@
 }
 
 packet LeReadSupportedStates : CommandPacket (op_code = LE_READ_SUPPORTED_STATES) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet LeReadSupportedStatesComplete : CommandComplete (command_op_code = LE_READ_SUPPORTED_STATES) {
+  status : ErrorCode,
+  le_states : 64,
 }
 
 packet LeReceiverTest : CommandPacket (op_code = LE_RECEIVER_TEST) {
@@ -1926,14 +2523,26 @@
   _payload_,  // placeholder (unimplemented)
 }
 
+packet LeAddDeviceToResolvingListComplete : CommandComplete (command_op_code = LE_ADD_DEVICE_TO_RESOLVING_LIST) {
+  status : ErrorCode,
+}
+
 packet LeRemoveDeviceFromResolvingList : LeSecurityCommand (op_code = LE_REMOVE_DEVICE_FROM_RESOLVING_LIST) {
   _payload_,  // placeholder (unimplemented)
 }
 
+packet LeRemoveDeviceFromResolvingListComplete : CommandComplete (command_op_code = LE_REMOVE_DEVICE_FROM_RESOLVING_LIST) {
+  status : ErrorCode,
+}
+
 packet LeClearResolvingList : LeSecurityCommand (op_code = LE_CLEAR_RESOLVING_LIST) {
   _payload_,  // placeholder (unimplemented)
 }
 
+packet LeClearResolvingListComplete : CommandComplete (command_op_code = LE_CLEAR_RESOLVING_LIST) {
+  status : ErrorCode,
+}
+
 packet LeReadResolvingListSize : LeSecurityCommand (op_code = LE_READ_RESOLVING_LIST_SIZE) {
   _payload_,  // placeholder (unimplemented)
 }
@@ -1955,7 +2564,19 @@
 }
 
 packet LeReadMaximumDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_DATA_LENGTH) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+struct LeMaximumDataLength {
+  supported_max_tx_octets : 16,
+  supported_max_tx_time: 16,
+  supported_max_rx_octets : 16,
+  supported_max_rx_time: 16,
+}
+
+
+packet LeReadMaximumDataLengthComplete : CommandComplete (command_op_code = LE_READ_MAXIMUM_DATA_LENGTH) {
+  status : ErrorCode,
+  le_maximum_data_length : LeMaximumDataLength,
 }
 
 packet LeReadPhy : LeConnectionManagementCommand (op_code = LE_READ_PHY) {
@@ -1999,11 +2620,19 @@
 }
 
 packet LeReadMaximumAdvertisingDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet LeReadMaximumAdvertisingDataLengthComplete : CommandComplete (command_op_code = LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) {
+  status : ErrorCode,
+  maximum_advertising_data_length : 16,
 }
 
 packet LeReadNumberOfSupportedAdvertisingSets : CommandPacket (op_code = LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) {
-  _payload_,  // placeholder (unimplemented)
+}
+
+packet LeReadNumberOfSupportedAdvertisingSetsComplete : CommandComplete (command_op_code = LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) {
+  status : ErrorCode,
+  number_supported_advertising_sets : 8,
 }
 
 packet LeRemoveAdvertisingSet : LeAdvertisingCommand (op_code = LE_REMOVE_ADVERTISING_SET) {
@@ -2026,12 +2655,33 @@
   _payload_,  // placeholder (unimplemented)
 }
 
-packet LeSetExtendedScanParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
-  _payload_,  // placeholder (unimplemented)
+packet LeSetExtendedScanParameters : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
+  le_scan_type : LeScanType,
+  le_scan_interval : 32, // 0x0004-0x00FFFFFF Default 0x10 (10ms)
+  le_scan_window : 32, // 0x004-0xFFFF Default 0x10 (10ms)
+  own_address_type : AddressType,
+  scanning_filter_policy : LeSetScanningFilterPolicy,
 }
 
-packet LeSetExtendedScanEnable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
-  _payload_,  // placeholder (unimplemented)
+packet LeSetExtendedScanParametersComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
+  status : ErrorCode,
+}
+
+enum FilterDuplicates : 8 {
+  DISABLED = 0,
+  ENABLED = 1,
+  RESET_EACH_PERIOD = 2,
+}
+
+packet LeSetExtendedScanEnable : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
+  enable : Enable,
+  filter_duplicates : FilterDuplicates,
+  duration : 16, // 0 - Scan continuously,  N * 10 ms
+  period : 16, // 0 - Scan continuously,  N * 1.28 sec
+}
+
+packet LeSetExtendedScanEnableComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
+  status : ErrorCode,
 }
 
 packet LeExtendedCreateConnection : LeConnectionManagementCommand (op_code = LE_EXTENDED_CREATE_CONNECTION) {
@@ -2082,22 +2732,158 @@
   _payload_,  // placeholder (unimplemented)
 }
 
+packet LeSetPrivacyModeComplete : CommandComplete (command_op_code = LE_SET_PRIVACY_MODE) {
+  status : ErrorCode,
+}
 
   // VENDOR_SPECIFIC
 packet LeGetVendorCapabilities : VendorCommand (op_code = LE_GET_VENDOR_CAPABILITIES) {
-  _payload_,  // placeholder (unimplemented)
 }
 
-packet LeMultiAdvt : VendorCommand (op_code = LE_MULTI_ADVT) {
-  _payload_,  // placeholder (unimplemented)
+struct VendorCapabilities {
+  is_supported : 8,
+  max_advt_instances: 8,
+  offloaded_resolution_of_private_address : 8,
+  total_scan_results_storage: 16,
+  max_irk_list_sz: 8,
+  filtering_support: 8,
+  max_filter: 8,
+  activity_energy_info_support: 8,
+  version_supported: 16,
+  total_num_of_advt_tracked: 16,
+  extended_scan_support: 8,
+  debug_logging_supported: 8,
+  le_address_generation_offloading_support: 8,
+  a2dp_source_offload_capability_mask: 32,
+  bluetooth_quality_report_support: 8
+}
+
+struct BaseVendorCapabilities {
+  max_advt_instances: 8,
+  offloaded_resolution_of_private_address : 8,
+  total_scan_results_storage: 16,
+  max_irk_list_sz: 8,
+  filtering_support: 8,
+  max_filter: 8,
+  activity_energy_info_support: 8,
+}
+
+packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) {
+  status : ErrorCode,
+  base_vendor_capabilities : BaseVendorCapabilities,
+  _payload_,
+}
+packet LeGetVendorCapabilitiesComplete095 : LeGetVendorCapabilitiesComplete {
+  version_supported: 16,
+  total_num_of_advt_tracked: 16,
+  extended_scan_support: 8,
+  debug_logging_supported: 8,
+  _payload_,
+}
+packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 {
+  le_address_generation_offloading_support: 8,
+  _payload_,
+}
+
+packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 {
+  a2dp_source_offload_capability_mask: 32,
+  bluetooth_quality_report_support: 8
+}
+
+enum SubOcf : 8 {
+  SET_PARAM = 0x01,
+  SET_DATA = 0x02,
+  SET_SCAN_RESP = 0x03,
+  SET_RANDOM_ADDR = 0x04,
+  SET_ENABLE = 0x05,
+}
+
+packet LeMultiAdvt : LeAdvertisingCommand (op_code = LE_MULTI_ADVT) {
+  sub_cmd : SubOcf,
+  _body_,
+}
+
+packet LeMultiAdvtComplete : CommandComplete (command_op_code = LE_MULTI_ADVT) {
+  status : ErrorCode,
+  sub_cmd : SubOcf,
+}
+
+packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_PARAM) {
+  interval_min : 16,
+  interval_max : 16,
+  type : AdvertisingEventType,
+  own_address_type : AddressType,
+  peer_address_type : PeerAddressType,
+  peer_address : Address,
+  channel_map : 8,
+  filter_policy : AdvertisingFilterPolicy,
+  _reserved_ : 6,
+  instance : 8,
+  tx_power : 8,
+}
+
+packet LeMultiAdvtParamComplete : LeMultiAdvtComplete (sub_cmd = SET_PARAM) {
+}
+
+packet LeMultiAdvtSetData : LeMultiAdvt (sub_cmd = SET_DATA) {
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+  _padding_[31], // Zero padding to 31 bytes of advertising_data
+  advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetDataComplete : LeMultiAdvtComplete (sub_cmd = SET_DATA) {
+}
+
+packet LeMultiAdvtSetScanResp : LeMultiAdvt (sub_cmd = SET_SCAN_RESP) {
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+  _padding_[31], // Zero padding to 31 bytes of advertising_data
+  advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetScanRespComplete : LeMultiAdvtComplete (sub_cmd = SET_SCAN_RESP) {
+}
+
+packet LeMultiAdvtSetRandomAddr : LeMultiAdvt (sub_cmd = SET_RANDOM_ADDR) {
+  random_address : Address,
+  advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetRandomAddrComplete : LeMultiAdvtComplete (sub_cmd = SET_RANDOM_ADDR) {
+}
+
+packet LeMultiAdvtSetEnable : LeMultiAdvt (sub_cmd = SET_ENABLE) {
+  advertising_enable : Enable, // Default DISABLED
+  advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetEnableComplete : LeMultiAdvtComplete (sub_cmd = SET_ENABLE) {
 }
 
 packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) {
   _payload_,  // placeholder (unimplemented)
 }
 
+enum ApcfOpcode : 8 {
+  ENABLE = 0x00,
+  SET_FILTERING_PARAMETERS = 0x01,
+  BROADCASTER_ADDRESS = 0x02,
+  SERVICE_UUID = 0x03,
+  SERVICE_SOLICITATION_UUID = 0x04,
+  LOCAL_NAME = 0x05,
+  MANUFACTURER_DATA = 0x06,
+  SERVICE_DATA = 0x07,
+}
+
 packet LeAdvFilter : VendorCommand (op_code = LE_ADV_FILTER) {
-  _payload_,  // placeholder (unimplemented)
+  apcf_opcode : ApcfOpcode,
+  _body_,
+}
+
+packet LeAdvFilterComplete : CommandComplete (command_op_code = LE_ADV_FILTER) {
+  status : ErrorCode,
+  apcf_opcode : ApcfOpcode,
 }
 
 packet LeTrackAdv : VendorCommand (op_code = LE_TRACK_ADV) {
@@ -2108,8 +2894,16 @@
   _payload_,  // placeholder (unimplemented)
 }
 
-packet LeExtendedScanParams : VendorCommand (op_code = LE_EXTENDED_SCAN_PARAMS) {
-  _payload_,  // placeholder (unimplemented)
+packet LeExtendedScanParams : LeScanningCommand (op_code = LE_EXTENDED_SCAN_PARAMS) {
+  le_scan_type : LeScanType,
+  le_scan_interval : 32, // 0x0004-0x4000 Default 0x10 (10ms)
+  le_scan_window : 32, // Default 0x10 (10ms)
+  own_address_type : AddressType,
+  scanning_filter_policy : LeSetScanningFilterPolicy,
+}
+
+packet LeExtendedScanParamsComplete : CommandComplete (command_op_code = LE_EXTENDED_SCAN_PARAMS) {
+  status : ErrorCode,
 }
 
 packet ControllerDebugInfo : VendorCommand (op_code = CONTROLLER_DEBUG_INFO) {
@@ -2179,7 +2973,7 @@
 packet RemoteNameRequestComplete : EventPacket (event_code = REMOTE_NAME_REQUEST_COMPLETE){
   status : ErrorCode,
   bd_addr : Address,
-  _payload_,
+  remote_name : 8[248], // UTF-8 encoded user-friendly descriptive name
 }
 
 enum EncryptionEnabled : 8 {
@@ -2220,14 +3014,8 @@
   connection_handle : 12,
   _reserved_ : 4,
   version : 8,
-  manufacturer_name : 8,
-  sub_version : 8,
-}
-
-enum ServiceType : 8 {
-  NO_TRAFFIC = 0x00,
-  BEST_EFFORT = 0x01,
-  GUARANTEED = 0x02,
+  manufacturer_name : 16,
+  sub_version : 16,
 }
 
 packet QosSetupComplete : EventPacket (event_code = QOS_SETUP_COMPLETE){
@@ -2253,11 +3041,6 @@
   _reserved_ : 4,
 }
 
-enum Role : 8 {
-  MASTER = 0x00,
-  SLAVE = 0x01,
-}
-
 packet RoleChange : EventPacket (event_code = ROLE_CHANGE){
   status : ErrorCode,
   bd_addr : Address,
@@ -2265,8 +3048,8 @@
 }
 
 packet NumberOfCompletedPackets : EventPacket (event_code = NUMBER_OF_COMPLETED_PACKETS){
-  _count_(handles_and_completed_packets) : 8,
-  handles_and_completed_packets : 32[], // connection_handle[i] : 12, _reserved_[i] : 4, hc_num_of_completed_packets[i] : 16
+  _count_(completed_packets) : 8,
+  completed_packets : CompletedPackets[],
 }
 
 enum Mode : 8 {
@@ -2283,8 +3066,15 @@
   interval : 16, // 0x002 - 0xFFFE (1.25ms - 40.9s)
 }
 
+struct ZeroKeyAndAddress {
+  address : Address,
+  _fixed_ = 0 : 64,
+  _fixed_ = 0 : 64,
+}
+
 packet ReturnLinkKeys : EventPacket (event_code = RETURN_LINK_KEYS){
-  _payload_, // placeholder (unimplemented)
+  _count_(keys) : 8,
+  keys : ZeroKeyAndAddress[],
 }
 
 packet PinCodeRequest : EventPacket (event_code = PIN_CODE_REQUEST){
@@ -2295,8 +3085,20 @@
   bd_addr : Address,
 }
 
+enum KeyType : 8 {
+  COMBINATION = 0x00,
+  DEBUG_COMBINATION = 0x03,
+  UNAUTHENTICATED_P192 = 0x04,
+  AUTHENTICATED_P192 = 0x05,
+  CHANGED = 0x06,
+  UNAUTHENTICATED_P256 = 0x07,
+  AUTHENTICATED_P256 = 0x08,
+}
+
 packet LinkKeyNotification : EventPacket (event_code = LINK_KEY_NOTIFICATION){
-  _payload_, // placeholder (unimplemented)
+  bd_addr : Address,
+  link_key : 8[16],
+  key_type : KeyType,
 }
 
 packet LoopbackCommand : EventPacket (event_code = LOOPBACK_COMMAND){
@@ -2321,7 +3123,7 @@
   _reserved_ : 1,
 }
 
-packet ConnectionPacketTypeChange : EventPacket (event_code = CONNECTION_PACKET_TYPE_CHANGE){
+packet ConnectionPacketTypeChanged : EventPacket (event_code = CONNECTION_PACKET_TYPE_CHANGED){
   status : ErrorCode,
   connection_handle : 12,
   _reserved_ : 4,
@@ -2337,7 +3139,16 @@
 }
 
 packet FlowSpecificationComplete : EventPacket (event_code = FLOW_SPECIFICATION_COMPLETE){
-  _payload_, // placeholder (unimplemented)
+  status : ErrorCode,
+  connection_handle : 12,
+  _reserved_ : 4,
+  _reserved_ : 8,
+  flow_direction : FlowDirection,
+  service_type : ServiceType,
+  token_rate : 32, // Octets/s
+  token_bucket_size : 32,
+  peak_bandwidth : 32, // Octets/s
+  access_latency : 32, // Octets/s
 }
 
 packet InquiryResultWithRssi : EventPacket (event_code = INQUIRY_RESULT_WITH_RSSI){
@@ -2387,7 +3198,7 @@
   clock_offset : 15,
   _reserved_ : 1,
   rssi : 8,
-  _payload_,
+  extended_inquiry_response : GapData[],
 }
 
 packet EncryptionKeyRefreshComplete : EventPacket (event_code = ENCRYPTION_KEY_REFRESH_COMPLETE){
@@ -2480,7 +3291,7 @@
   connection_handle : 12,
   _reserved_ : 4,
   role : Role,
-  peer_address_type : PeerAddressType,
+  peer_address_type : AddressType,
   peer_address : Address,
   conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
   conn_latency : 16,  // Number of connection events
@@ -2488,8 +3299,18 @@
   master_clock_accuracy : MasterClockAccuracy,
 }
 
+struct LeAdvertisingReport {
+  event_type : AdvertisingEventType,
+  address_type : AddressType,
+  address : Address,
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+  rssi : 8,
+}
+
 packet LeAdvertisingReport : LeMetaEvent (subevent_code = ADVERTISING_REPORT) {
-  _payload_,
+  _count_(advertising_reports) : 8,
+  advertising_reports : LeAdvertisingReport[],
 }
 
 packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDATE_COMPLETE) {
@@ -2536,12 +3357,12 @@
 
 packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) {
   status : ErrorCode,
-  _payload_,
+  local_p_256_public_key : 8[64],
 }
 
 packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) {
   status : ErrorCode,
-  _payload_,
+  dh_key : 8[32],
 }
 
 packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONNECTION_COMPLETE) {
@@ -2549,7 +3370,7 @@
   connection_handle : 12,
   _reserved_ : 4,
   role : Role,
-  peer_address_type : PeerAddressType,
+  peer_address_type : AddressType,
   peer_address : Address,
   local_resolvable_private_address : Address,
   peer_resolvable_private_address : Address,
@@ -2564,6 +3385,7 @@
   RANDOM_DEVICE_ADDRESS = 0x01,
   PUBLIC_IDENTITY_ADDRESS = 0x02,
   RANDOM_IDENTITY_ADDRESS = 0x03,
+  CONTROLLER_UNABLE_TO_RESOLVE = 0xFE,
   NO_ADDRESS = 0xFF,
 }
 
@@ -2575,16 +3397,69 @@
   RANDOM_DEVICE_ADDRESS = 0x01,
 }
 
+struct LeDirectedAdvertisingReport {
+  event_type : DirectAdvertisingEventType,
+  address_type : DirectAdvertisingAddressType,
+  address : Address,
+  direct_address_type : DirectAddressType,
+  direct_address : Address,
+  rssi : 8,
+}
+
 packet LeDirectedAdvertisingReport : LeMetaEvent (subevent_code = DIRECTED_ADVERTISING_REPORT) {
-  _payload_, // placeholder (unimplemented)
+  _count_(advertising_reports) : 8,
+  advertising_reports : LeDirectedAdvertisingReport[],
 }
 
 packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) {
   _payload_, // placeholder (unimplemented)
 }
 
+enum DataStatus : 2 {
+  COMPLETE = 0x0,
+  CONTINUING = 0x1,
+  TRUNCATED = 0x2,
+  RESERVED = 0x3,
+}
+
+enum PrimaryPhyType : 8 {
+  LE_1M = 0x01,
+  LE_CODED = 0x03,
+}
+
+enum SecondaryPhyType : 8 {
+  NO_PACKETS = 0x00,
+  LE_1M = 0x01,
+  LE_2M = 0x02,
+  LE_CODED = 0x03,
+}
+
+
+struct LeExtendedAdvertisingReport {
+  connectable : 1,
+  scannable : 1,
+  directed : 1,
+  scan_response : 1,
+  data_status : DataStatus,
+  _reserved_ : 10,
+  address_type : DirectAdvertisingAddressType,
+  address : Address,
+  primary_phy : PrimaryPhyType,
+  secondary_phy : SecondaryPhyType,
+  advertising_sid : 4, // SID subfield in the ADI field
+  _reserved_ : 4,
+  tx_power : 8,
+  rssi : 8, // -127 to +20 (0x7F means not available)
+  periodic_advertising_interval : 16, // 0x006 to 0xFFFF (7.5 ms to 82s)
+  direct_address_type : DirectAdvertisingAddressType,
+  direct_address : Address,
+  _size_(advertising_data) : 8,
+  advertising_data : GapData[],
+}
+
 packet LeExtendedAdvertisingReport : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) {
-  _payload_, // placeholder (unimplemented)
+  _count_(advertising_reports) : 8,
+  advertising_reports : LeExtendedAdvertisingReport[],
 }
 
 packet LePeriodicAdvertisingSyncEstablished : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_ESTABLISHED) {
@@ -2603,9 +3478,15 @@
 }
 
 packet LeAdvertisingSetTerminated : LeMetaEvent (subevent_code = ADVERTISING_SET_TERMINATED) {
-  _payload_, // placeholder (unimplemented)
+  status : ErrorCode,
+  advertising_handle : 8,
+  connection_handle : 12,
+  _reserved_ : 4,
+  num_completed_extended_advertising_events : 8,
 }
 
 packet LeScanRequestReceived : LeMetaEvent (subevent_code = SCAN_REQUEST_RECEIVED) {
-  _payload_, // placeholder (unimplemented)
+  advertising_handle : 8,
+  scanner_address_type : AddressType,
+  scanner_address : Address,
 }
diff --git a/gd/hci/hci_packets_fuzz_test.cc b/gd/hci/hci_packets_fuzz_test.cc
new file mode 100644
index 0000000..5ef3ef6
--- /dev/null
+++ b/gd/hci/hci_packets_fuzz_test.cc
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#define PACKET_FUZZ_TESTING
+#include "hci/hci_packets.h"
+
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace hci {
+
+std::vector<void (*)(const uint8_t*, size_t)> hci_packet_fuzz_tests;
+
+DEFINE_AND_REGISTER_ResetReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ResetCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_HostBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_HostBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalVersionInformationReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalVersionInformationCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBdAddrReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBdAddrCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalSupportedCommandsReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalSupportedCommandsCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSimplePairingModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSimplePairingModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteLeHostSupportReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteLeHostSupportCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalExtendedFeaturesReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalExtendedFeaturesCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSecureConnectionsHostSupportReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSecureConnectionsHostSupportCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadWhiteListSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadWhiteListSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteCurrentIacLapReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteCurrentIacLapCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteInquiryScanActivityReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteInquiryScanActivityCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadInquiryScanActivityReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadInquiryScanActivityCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadCurrentIacLapReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadCurrentIacLapCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadNumberOfSupportedIacReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadNumberOfSupportedIacCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadPageTimeoutReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadPageTimeoutCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WritePageTimeoutReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WritePageTimeoutCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryStatusReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryCancelReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryCancelCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_PeriodicInquiryModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_PeriodicInquiryModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ExitPeriodicInquiryModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ExitPeriodicInquiryModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+}  // namespace hci
+}  // namespace bluetooth
+
+void RunHciPacketFuzzTest(const uint8_t* data, size_t size) {
+  if (data == nullptr) return;
+  for (auto test_function : bluetooth::hci::hci_packet_fuzz_tests) {
+    test_function(data, size);
+  }
+}
\ No newline at end of file
diff --git a/gd/hci/hci_packets_test.cc b/gd/hci/hci_packets_test.cc
new file mode 100644
index 0000000..729513b
--- /dev/null
+++ b/gd/hci/hci_packets_test.cc
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+#define PACKET_TESTING
+#include "hci/hci_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace hci {
+
+std::vector<uint8_t> reset = {0x03, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ResetReflectionTest(reset);
+
+std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ResetCompleteReflectionTest(reset_complete);
+
+std::vector<uint8_t> read_buffer_size = {0x05, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBufferSizeReflectionTest(read_buffer_size);
+
+std::vector<uint8_t> read_buffer_size_complete = {0x0e, 0x0b, 0x01, 0x05, 0x10, 0x00, 0x00,
+                                                  0x04, 0x3c, 0x07, 0x00, 0x08, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBufferSizeCompleteReflectionTest(read_buffer_size_complete);
+
+std::vector<uint8_t> host_buffer_size = {0x33, 0x0c, 0x07, 0x9b, 0x06, 0xff, 0x14, 0x00, 0x0a, 0x00};
+DEFINE_AND_INSTANTIATE_HostBufferSizeReflectionTest(host_buffer_size);
+
+std::vector<uint8_t> host_buffer_size_complete = {0x0e, 0x04, 0x01, 0x33, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_HostBufferSizeCompleteReflectionTest(host_buffer_size_complete);
+
+std::vector<uint8_t> read_local_version_information = {0x01, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalVersionInformationReflectionTest(read_local_version_information);
+
+std::vector<uint8_t> read_local_version_information_complete = {0x0e, 0x0c, 0x01, 0x01, 0x10, 0x00, 0x09,
+                                                                0x00, 0x00, 0x09, 0x1d, 0x00, 0xbe, 0x02};
+DEFINE_AND_INSTANTIATE_ReadLocalVersionInformationCompleteReflectionTest(read_local_version_information_complete);
+
+std::vector<uint8_t> read_bd_addr = {0x09, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBdAddrReflectionTest(read_bd_addr);
+
+std::vector<uint8_t> read_bd_addr_complete = {0x0e, 0x0a, 0x01, 0x09, 0x10, 0x00, 0x14, 0x8e, 0x61, 0x5f, 0x36, 0x88};
+DEFINE_AND_INSTANTIATE_ReadBdAddrCompleteReflectionTest(read_bd_addr_complete);
+
+std::vector<uint8_t> read_local_supported_commands = {0x02, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalSupportedCommandsReflectionTest(read_local_supported_commands);
+
+std::vector<uint8_t> read_local_supported_commands_complete = {
+    0x0e, 0x44, 0x01, 0x02, 0x10, 0x00, /* Supported commands start here (total 64 bytes) */
+    0xff, 0xff, 0xff, 0x03, 0xce, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf2, 0x0f, 0xe8, 0xfe,
+    0x3f, 0xf7, 0x83, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x61, 0xff, 0xff, 0xff, 0x7f, 0xbe, 0x20, 0xf5,
+    0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalSupportedCommandsCompleteReflectionTest(read_local_supported_commands_complete);
+
+std::vector<uint8_t> read_local_extended_features_0 = {0x04, 0x10, 0x01, 0x00};
+
+std::vector<uint8_t> read_local_extended_features_complete_0 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02,
+                                                                0xff, 0xfe, 0x8f, 0xfe, 0xd8, 0x3f, 0x5b, 0x87};
+
+std::vector<uint8_t> write_simple_paring_mode = {0x56, 0x0c, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteSimplePairingModeReflectionTest(write_simple_paring_mode);
+
+std::vector<uint8_t> write_simple_paring_mode_complete = {0x0e, 0x04, 0x01, 0x56, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteSimplePairingModeCompleteReflectionTest(write_simple_paring_mode_complete);
+
+std::vector<uint8_t> write_le_host_supported = {0x6d, 0x0c, 0x02, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteLeHostSupportReflectionTest(write_le_host_supported);
+
+std::vector<uint8_t> write_le_host_supported_complete = {0x0e, 0x04, 0x01, 0x6d, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteLeHostSupportCompleteReflectionTest(write_le_host_supported_complete);
+
+std::vector<uint8_t> read_local_extended_features_1 = {0x04, 0x10, 0x01, 0x01};
+
+std::vector<uint8_t> read_local_extended_features_complete_1 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x01, 0x02,
+                                                                0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> read_local_extended_features_2 = {0x04, 0x10, 0x01, 0x02};
+DEFINE_AND_INSTANTIATE_ReadLocalExtendedFeaturesReflectionTest(read_local_extended_features_0,
+                                                               read_local_extended_features_1,
+                                                               read_local_extended_features_2);
+
+std::vector<uint8_t> read_local_extended_features_complete_2 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x02, 0x02,
+                                                                0x45, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalExtendedFeaturesCompleteReflectionTest(read_local_extended_features_complete_0,
+                                                                       read_local_extended_features_complete_1,
+                                                                       read_local_extended_features_complete_2);
+
+std::vector<uint8_t> write_secure_connections_host_support = {0x7a, 0x0c, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteSecureConnectionsHostSupportReflectionTest(write_secure_connections_host_support);
+
+std::vector<uint8_t> write_secure_connections_host_support_complete = {0x0e, 0x04, 0x01, 0x7a, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteSecureConnectionsHostSupportCompleteReflectionTest(
+    write_secure_connections_host_support_complete);
+
+std::vector<uint8_t> le_read_white_list_size = {0x0f, 0x20, 0x00};
+DEFINE_AND_INSTANTIATE_LeReadWhiteListSizeReflectionTest(le_read_white_list_size);
+
+std::vector<uint8_t> le_read_white_list_size_complete = {0x0e, 0x05, 0x01, 0x0f, 0x20, 0x00, 0x80};
+DEFINE_AND_INSTANTIATE_LeReadWhiteListSizeCompleteReflectionTest(le_read_white_list_size_complete);
+
+std::vector<uint8_t> le_read_buffer_size = {0x02, 0x20, 0x00};
+DEFINE_AND_INSTANTIATE_LeReadBufferSizeReflectionTest(le_read_buffer_size);
+
+std::vector<uint8_t> le_read_buffer_size_complete = {0x0e, 0x07, 0x01, 0x02, 0x20, 0x00, 0xfb, 0x00, 0x10};
+DEFINE_AND_INSTANTIATE_LeReadBufferSizeCompleteReflectionTest(le_read_buffer_size_complete);
+
+std::vector<uint8_t> write_current_iac_laps = {0x3a, 0x0c, 0x07, 0x02, 0x11, 0x8b, 0x9e, 0x22, 0x8b, 0x9e};
+DEFINE_AND_INSTANTIATE_WriteCurrentIacLapReflectionTest(write_current_iac_laps);
+
+std::vector<uint8_t> write_current_iac_laps_complete = {0x0e, 0x04, 0x01, 0x3a, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteCurrentIacLapCompleteReflectionTest(write_current_iac_laps_complete);
+
+std::vector<uint8_t> write_inquiry_scan_activity = {0x1e, 0x0c, 0x04, 0x00, 0x08, 0x12, 0x00};
+DEFINE_AND_INSTANTIATE_WriteInquiryScanActivityReflectionTest(write_inquiry_scan_activity);
+
+std::vector<uint8_t> write_inquiry_scan_activity_complete = {0x0e, 0x04, 0x01, 0x1e, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteInquiryScanActivityCompleteReflectionTest(write_inquiry_scan_activity_complete);
+
+std::vector<uint8_t> read_inquiry_scan_activity = {0x1d, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadInquiryScanActivityReflectionTest(read_inquiry_scan_activity);
+
+std::vector<uint8_t> read_inquiry_scan_activity_complete = {0x0e, 0x08, 0x01, 0x1d, 0x0c, 0x00, 0xaa, 0xbb, 0xcc, 0xdd};
+DEFINE_AND_INSTANTIATE_ReadInquiryScanActivityCompleteReflectionTest(read_inquiry_scan_activity_complete);
+
+std::vector<uint8_t> read_current_iac_lap = {0x39, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadCurrentIacLapReflectionTest(read_current_iac_lap);
+
+std::vector<uint8_t> read_current_iac_lap_complete = {0x0e, 0x0b, 0x01, 0x39, 0x0c, 0x00, 0x02,
+                                                      0x11, 0x8b, 0x9e, 0x22, 0x8b, 0x9e};
+DEFINE_AND_INSTANTIATE_ReadCurrentIacLapCompleteReflectionTest(read_current_iac_lap_complete);
+
+std::vector<uint8_t> read_number_of_supported_iac = {0x38, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadNumberOfSupportedIacReflectionTest(read_number_of_supported_iac);
+
+std::vector<uint8_t> read_number_of_supported_iac_complete = {0x0e, 0x05, 0x01, 0x38, 0x0c, 0x00, 0x99};
+DEFINE_AND_INSTANTIATE_ReadNumberOfSupportedIacCompleteReflectionTest(read_number_of_supported_iac_complete);
+
+std::vector<uint8_t> read_page_timeout = {0x17, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadPageTimeoutReflectionTest(read_page_timeout);
+
+std::vector<uint8_t> read_page_timeout_complete = {0x0e, 0x06, 0x01, 0x17, 0x0c, 0x00, 0x11, 0x22};
+DEFINE_AND_INSTANTIATE_ReadPageTimeoutCompleteReflectionTest(read_page_timeout_complete);
+
+std::vector<uint8_t> write_page_timeout = {0x18, 0x0c, 0x02, 0x00, 0x20};
+DEFINE_AND_INSTANTIATE_WritePageTimeoutReflectionTest(write_page_timeout);
+
+std::vector<uint8_t> write_page_timeout_complete = {0x0e, 0x04, 0x01, 0x18, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WritePageTimeoutCompleteReflectionTest(write_page_timeout_complete);
+
+std::vector<uint8_t> inquiry = {0x01, 0x04, 0x05, 0x33, 0x8b, 0x9e, 0xaa, 0xbb};
+DEFINE_AND_INSTANTIATE_InquiryReflectionTest(inquiry);
+
+std::vector<uint8_t> inquiry_status = {0x0f, 0x04, 0x00, 0x01, 0x01, 0x04};
+DEFINE_AND_INSTANTIATE_InquiryStatusReflectionTest(inquiry_status);
+
+std::vector<uint8_t> inquiry_cancel = {0x02, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_InquiryCancelReflectionTest(inquiry_cancel);
+
+std::vector<uint8_t> inquiry_cancel_complete = {0x0e, 0x04, 0x01, 0x02, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_InquiryCancelCompleteReflectionTest(inquiry_cancel_complete);
+
+std::vector<uint8_t> periodic_inquiry_mode = {0x03, 0x04, 0x09, 0x12, 0x34, 0x56, 0x78, 0x11, 0x8b, 0x9e, 0x9a, 0xbc};
+DEFINE_AND_INSTANTIATE_PeriodicInquiryModeReflectionTest(periodic_inquiry_mode);
+
+std::vector<uint8_t> periodic_inquiry_mode_complete = {0x0e, 0x04, 0x01, 0x03, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_PeriodicInquiryModeCompleteReflectionTest(periodic_inquiry_mode_complete);
+
+std::vector<uint8_t> exit_periodic_inquiry_mode = {0x04, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_ExitPeriodicInquiryModeReflectionTest(exit_periodic_inquiry_mode);
+
+std::vector<uint8_t> exit_periodic_inquiry_mode_complete = {0x0e, 0x04, 0x01, 0x04, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_ExitPeriodicInquiryModeCompleteReflectionTest(exit_periodic_inquiry_mode_complete);
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response{
+    0x52, 0x0c, 0xf1, 0x01, 0x0b, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58, 0x4c, 0x19, 0x03, 0x05,
+    0x11, 0x0a, 0x11, 0x0c, 0x11, 0x0e, 0x11, 0x12, 0x11, 0x15, 0x11, 0x16, 0x11, 0x1f, 0x11, 0x2d, 0x11, 0x2f, 0x11,
+    0x00, 0x12, 0x32, 0x11, 0x01, 0x05, 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response_no_uuids{
+    0x52, 0x0c, 0xf1, 0x01, 0x0b, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58, 0x4c, 0x01, 0x03, 0x01,
+    0x05, 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response_no_uuids_just_eir{
+    pixel_3_xl_write_extended_inquiry_response_no_uuids.begin() + 4,  // skip command, size, and fec_required
+    pixel_3_xl_write_extended_inquiry_response_no_uuids.end()};
+
+TEST(HciPacketsTest, testWriteExtendedInquiryResponse) {
+  std::shared_ptr<std::vector<uint8_t>> view_bytes =
+      std::make_shared<std::vector<uint8_t>>(pixel_3_xl_write_extended_inquiry_response);
+
+  PacketView<kLittleEndian> packet_bytes_view(view_bytes);
+  auto view = WriteExtendedInquiryResponseView::Create(CommandPacketView::Create(packet_bytes_view));
+  ASSERT_TRUE(view.IsValid());
+  auto gap_data = view.GetExtendedInquiryResponse();
+  ASSERT_GE(gap_data.size(), 4);
+  ASSERT_EQ(gap_data[0].data_type_, GapDataType::COMPLETE_LOCAL_NAME);
+  ASSERT_EQ(gap_data[0].data_.size(), 10);
+  ASSERT_EQ(gap_data[1].data_type_, GapDataType::COMPLETE_LIST_16_BIT_UUIDS);
+  ASSERT_EQ(gap_data[1].data_.size(), 24);
+  ASSERT_EQ(gap_data[2].data_type_, GapDataType::COMPLETE_LIST_32_BIT_UUIDS);
+  ASSERT_EQ(gap_data[2].data_.size(), 0);
+  ASSERT_EQ(gap_data[3].data_type_, GapDataType::COMPLETE_LIST_128_BIT_UUIDS);
+  ASSERT_EQ(gap_data[3].data_.size(), 128);
+
+  std::vector<GapData> no_padding{gap_data.begin(), gap_data.begin() + 4};
+  auto builder = WriteExtendedInquiryResponseBuilder::Create(view.GetFecRequired(), no_padding);
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  builder->Serialize(it);
+
+  EXPECT_EQ(packet_bytes->size(), view_bytes->size());
+  for (size_t i = 0; i < view_bytes->size(); i++) {
+    ASSERT_EQ(packet_bytes->at(i), view_bytes->at(i));
+  }
+}
+
+//  TODO: Revisit reflection tests for EIR
+// DEFINE_AND_INSTANTIATE_WriteExtendedInquiryResponseReflectionTest(pixel_3_xl_write_extended_inquiry_response,
+// pixel_3_xl_write_extended_inquiry_response_no_uuids);
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/le_advertising_interface.h b/gd/hci/le_advertising_interface.h
new file mode 100644
index 0000000..f915c02
--- /dev/null
+++ b/gd/hci/le_advertising_interface.h
@@ -0,0 +1,45 @@
+/*
+ * 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 "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeAdvertisingInterface {
+ public:
+  LeAdvertisingInterface() = default;
+  virtual ~LeAdvertisingInterface() = default;
+  DISALLOW_COPY_AND_ASSIGN(LeAdvertisingInterface);
+
+  virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+  static constexpr hci::SubeventCode LeAdvertisingEvents[] = {
+      hci::SubeventCode::SCAN_REQUEST_RECEIVED,
+      hci::SubeventCode::ADVERTISING_SET_TERMINATED,
+  };
+};
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/le_advertising_manager.cc b/gd/hci/le_advertising_manager.cc
new file mode 100644
index 0000000..3362ea3
--- /dev/null
+++ b/gd/hci/le_advertising_manager.cc
@@ -0,0 +1,330 @@
+/*
+ * 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 <memory>
+#include <mutex>
+
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "hci/le_advertising_interface.h"
+#include "hci/le_advertising_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hci {
+
+const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); });
+
+enum class AdvertisingApiType {
+  LE_4_0 = 1,
+  ANDROID_HCI = 2,
+  LE_5_0 = 3,
+};
+
+struct Advertiser {
+  os::Handler* handler;
+  common::Callback<void(Address, AddressType)> scan_callback;
+  common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback;
+};
+
+struct LeAdvertisingManager::impl {
+  impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {}
+
+  void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
+    module_handler_ = handler;
+    hci_layer_ = hci_layer;
+    controller_ = controller;
+    le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface(
+        common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_);
+    num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets();
+    if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) {
+      advertising_api_type_ = AdvertisingApiType::LE_5_0;
+    } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) {
+      advertising_api_type_ = AdvertisingApiType::ANDROID_HCI;
+    } else {
+      advertising_api_type_ = AdvertisingApiType::LE_4_0;
+    }
+  }
+
+  size_t GetNumberOfAdvertisingInstances() const {
+    return num_instances_;
+  }
+
+  void handle_event(LeMetaEventView event) {
+    switch (event.GetSubeventCode()) {
+      case hci::SubeventCode::SCAN_REQUEST_RECEIVED:
+        handle_scan_request(LeScanRequestReceivedView::Create(event));
+        break;
+      case hci::SubeventCode::ADVERTISING_SET_TERMINATED:
+        handle_set_terminated(LeAdvertisingSetTerminatedView::Create(event));
+        break;
+      default:
+        LOG_INFO("Unknown subevent in scanner %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
+    }
+  }
+
+  void handle_scan_request(LeScanRequestReceivedView event_view) {
+    if (!event_view.IsValid()) {
+      LOG_INFO("Dropping invalid scan request event");
+      return;
+    }
+    registered_handler_->Post(
+        common::BindOnce(scan_callback_, event_view.GetScannerAddress(), event_view.GetScannerAddressType()));
+  }
+
+  void handle_set_terminated(LeAdvertisingSetTerminatedView event_view) {
+    if (!event_view.IsValid()) {
+      LOG_INFO("Dropping invalid advertising event");
+      return;
+    }
+    registered_handler_->Post(common::BindOnce(set_terminated_callback_, event_view.GetStatus(),
+                                               event_view.GetAdvertisingHandle(),
+                                               event_view.GetNumCompletedExtendedAdvertisingEvents()));
+  }
+
+  AdvertiserId allocate_advertiser() {
+    AdvertiserId id = 0;
+    {
+      std::unique_lock lock(id_mutex_);
+      while (id < num_instances_ && advertising_sets_.count(id) != 0) {
+        id++;
+      }
+    }
+    if (id == num_instances_) {
+      return kInvalidId;
+    }
+    return id;
+  }
+
+  void remove_advertiser(AdvertiserId id) {
+    std::unique_lock lock(id_mutex_);
+    if (advertising_sets_.count(id) == 0) {
+      return;
+    }
+    advertising_sets_.erase(id);
+  }
+
+  void create_advertiser(AdvertiserId id, const AdvertisingConfig& config,
+                         const common::Callback<void(Address, AddressType)>& scan_callback,
+                         const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+                         os::Handler* handler) {
+    advertising_sets_[id].scan_callback = scan_callback;
+    advertising_sets_[id].set_terminated_callback = set_terminated_callback;
+    advertising_sets_[id].handler = handler;
+    switch (advertising_api_type_) {
+      case (AdvertisingApiType::LE_4_0):
+        le_advertising_interface_->EnqueueCommand(
+            hci::LeSetAdvertisingParametersBuilder::Create(
+                config.interval_min, config.interval_max, config.event_type, config.address_type,
+                config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy),
+            common::BindOnce(impl::check_status<LeSetAdvertisingParametersCompleteView>), module_handler_);
+        le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address),
+                                                  common::BindOnce(impl::check_status<LeSetRandomAddressCompleteView>),
+                                                  module_handler_);
+        if (!config.scan_response.empty()) {
+          le_advertising_interface_->EnqueueCommand(
+              hci::LeSetScanResponseDataBuilder::Create(config.scan_response),
+              common::BindOnce(impl::check_status<LeSetScanResponseDataCompleteView>), module_handler_);
+        }
+        le_advertising_interface_->EnqueueCommand(
+            hci::LeSetAdvertisingDataBuilder::Create(config.advertisement),
+            common::BindOnce(impl::check_status<LeSetAdvertisingDataCompleteView>), module_handler_);
+        le_advertising_interface_->EnqueueCommand(
+            hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED),
+            common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_);
+        break;
+      case (AdvertisingApiType::ANDROID_HCI):
+        le_advertising_interface_->EnqueueCommand(
+            hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type,
+                                                 config.address_type, config.peer_address_type, config.peer_address,
+                                                 config.channel_map, config.filter_policy, id, config.tx_power),
+            common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+        le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetDataBuilder::Create(config.advertisement, id),
+                                                  common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
+                                                  module_handler_);
+        if (!config.scan_response.empty()) {
+          le_advertising_interface_->EnqueueCommand(
+              hci::LeMultiAdvtSetScanRespBuilder::Create(config.scan_response, id),
+              common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+        }
+        le_advertising_interface_->EnqueueCommand(
+            hci::LeMultiAdvtSetRandomAddrBuilder::Create(config.random_address, id),
+            common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+        le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetEnableBuilder::Create(Enable::ENABLED, id),
+                                                  common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
+                                                  module_handler_);
+        break;
+      case (AdvertisingApiType::LE_5_0): {
+        ExtendedAdvertisingConfig new_config;
+        AdvertisingConfig* base_config_ptr = &new_config;
+        *(base_config_ptr) = config;
+        create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler);
+      } break;
+    }
+  }
+
+  void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config,
+                                  const common::Callback<void(Address, AddressType)>& scan_callback,
+                                  const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+                                  os::Handler* handler) {
+    if (advertising_api_type_ != AdvertisingApiType::LE_5_0) {
+      create_advertiser(id, config, scan_callback, set_terminated_callback, handler);
+      return;
+    }
+    LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented.");
+
+    /*
+    le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min,
+    config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address,
+    config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_status),
+    module_handler_);
+     */
+    advertising_sets_[id].scan_callback = scan_callback;
+    advertising_sets_[id].set_terminated_callback = set_terminated_callback;
+    advertising_sets_[id].handler = handler;
+  }
+
+  void stop_advertising(AdvertiserId advertising_set) {
+    if (advertising_sets_.find(advertising_set) == advertising_sets_.end()) {
+      LOG_INFO("Unknown advertising set %u", advertising_set);
+      return;
+    }
+    le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED),
+                                              common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>),
+                                              module_handler_);
+    std::unique_lock lock(id_mutex_);
+    advertising_sets_.erase(advertising_set);
+  }
+
+  common::Callback<void(Address, AddressType)> scan_callback_;
+  common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_;
+  os::Handler* registered_handler_{nullptr};
+  Module* module_;
+  os::Handler* module_handler_;
+  hci::HciLayer* hci_layer_;
+  hci::Controller* controller_;
+  hci::LeAdvertisingInterface* le_advertising_interface_;
+  std::map<AdvertiserId, Advertiser> advertising_sets_;
+
+  std::mutex id_mutex_;
+  size_t num_instances_;
+
+  AdvertisingApiType advertising_api_type_{0};
+
+  template <class View>
+  static void check_status(CommandCompleteView view) {
+    ASSERT(view.IsValid());
+    auto status_view = View::Create(view);
+    ASSERT(status_view.IsValid());
+    if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+      LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str());
+    }
+  }
+};
+
+LeAdvertisingManager::LeAdvertisingManager() {
+  pimpl_ = std::make_unique<impl>(this);
+}
+
+void LeAdvertisingManager::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+  list->add<hci::Controller>();
+}
+
+void LeAdvertisingManager::Start() {
+  pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
+}
+
+void LeAdvertisingManager::Stop() {
+  pimpl_.reset();
+}
+
+std::string LeAdvertisingManager::ToString() const {
+  return "Le Advertising Manager";
+}
+
+size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const {
+  return pimpl_->GetNumberOfAdvertisingInstances();
+}
+
+AdvertiserId LeAdvertisingManager::CreateAdvertiser(
+    const AdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
+    const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
+  if (config.peer_address == Address::kEmpty) {
+    if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS ||
+        config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) {
+      LOG_WARN("Peer address can not be empty");
+      return kInvalidId;
+    }
+    if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND ||
+        config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) {
+      LOG_WARN("Peer address can not be empty for directed advertising");
+      return kInvalidId;
+    }
+  }
+  AdvertiserId id = pimpl_->allocate_advertiser();
+  if (id == kInvalidId) {
+    return id;
+  }
+  GetHandler()->Post(common::BindOnce(&impl::create_advertiser, common::Unretained(pimpl_.get()), id, config,
+                                      scan_callback, set_terminated_callback, handler));
+  return id;
+}
+
+AdvertiserId LeAdvertisingManager::CreateAdvertiser(
+    const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
+    const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
+  if (config.directed) {
+    if (config.peer_address == Address::kEmpty) {
+      LOG_INFO("Peer address can not be empty for directed advertising");
+      return kInvalidId;
+    }
+  }
+  if (config.channel_map == 0) {
+    LOG_INFO("At least one channel must be set in the map");
+    return kInvalidId;
+  }
+  if (!config.legacy_pdus) {
+    if (config.connectable && config.scannable) {
+      LOG_INFO("Extended advertising PDUs can not be connectable and scannable");
+      return kInvalidId;
+    }
+    if (config.high_duty_directed_connectable) {
+      LOG_INFO("Extended advertising PDUs can not be high duty cycle");
+      return kInvalidId;
+    }
+  }
+  if (config.interval_min > config.interval_max) {
+    LOG_INFO("Advertising interval: min (%hu) > max (%hu)", config.interval_min, config.interval_max);
+    return kInvalidId;
+  }
+  AdvertiserId id = pimpl_->allocate_advertiser();
+  if (id == kInvalidId) {
+    return id;
+  }
+  GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config,
+                                      scan_callback, set_terminated_callback, handler));
+  return id;
+}
+
+void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) {
+  pimpl_->remove_advertiser(id);
+}
+
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_advertising_manager.h b/gd/hci/le_advertising_manager.h
new file mode 100644
index 0000000..4bbcfc1
--- /dev/null
+++ b/gd/hci/le_advertising_manager.h
@@ -0,0 +1,97 @@
+/*
+ * 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 <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AdvertisingConfig {
+ public:
+  std::vector<GapData> advertisement;
+  std::vector<GapData> scan_response;
+  Address random_address;
+  uint16_t interval_min;
+  uint16_t interval_max;
+  AdvertisingEventType event_type;
+  AddressType address_type;
+  PeerAddressType peer_address_type;
+  Address peer_address;
+  uint8_t channel_map;
+  AdvertisingFilterPolicy filter_policy;
+  uint8_t tx_power;  // -127 to +20 (0x7f is no preference)
+};
+
+class ExtendedAdvertisingConfig : public AdvertisingConfig {
+ public:
+  bool connectable;
+  bool scannable;
+  bool directed;
+  bool high_duty_directed_connectable;
+  bool legacy_pdus;
+  bool anonymous;
+  bool include_tx_power;
+  bool use_le_coded_phy;       // Primary advertisement PHY is LE Coded
+  uint8_t secondary_max_skip;  // maximum advertising events to be skipped, 0x0 send AUX_ADV_IND prior ot the next event
+  uint8_t secondary_advertising_phy;  // 1 = 1M, 2 = 2M, 3 = coded
+  uint8_t sid;
+  bool enable_scan_request_notifications;
+};
+
+using AdvertiserId = int32_t;
+
+class LeAdvertisingManager : public bluetooth::Module {
+ public:
+  static constexpr AdvertiserId kInvalidId = -1;
+  LeAdvertisingManager();
+
+  size_t GetNumberOfAdvertisingInstances() const;
+
+  // Return -1 if the advertiser was not created, otherwise the advertiser ID.
+  AdvertiserId CreateAdvertiser(const AdvertisingConfig& config,
+                                const common::Callback<void(Address, AddressType)>& scan_callback,
+                                const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+                                os::Handler* handler);
+  AdvertiserId CreateAdvertiser(const ExtendedAdvertisingConfig& config,
+                                const common::Callback<void(Address, AddressType)>& scan_callback,
+                                const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+                                os::Handler* handler);
+
+  void RemoveAdvertiser(AdvertiserId id);
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+
+  void Start() override;
+
+  void Stop() override;
+
+  std::string ToString() const override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(LeAdvertisingManager);
+};
+
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_advertising_manager_test.cc b/gd/hci/le_advertising_manager_test.cc
new file mode 100644
index 0000000..c4f40ad
--- /dev/null
+++ b/gd/hci/le_advertising_manager_test.cc
@@ -0,0 +1,356 @@
+/*
+ * 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 "hci/le_advertising_manager.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestController : public Controller {
+ public:
+  bool IsSupported(OpCode op_code) const override {
+    return supported_opcodes_.count(op_code) == 1;
+  }
+
+  void AddSupported(OpCode op_code) {
+    supported_opcodes_.insert(op_code);
+  }
+
+  uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const override {
+    return num_advertisers;
+  }
+
+  uint16_t num_advertisers{0};
+
+ protected:
+  void Start() override {}
+  void Stop() override {}
+  void ListDependencies(ModuleList* list) override {}
+
+ private:
+  std::set<OpCode> supported_opcodes_{};
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+  TestHciLayer() {
+    RegisterEventHandler(EventCode::COMMAND_COMPLETE,
+                         base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr);
+    RegisterEventHandler(EventCode::COMMAND_STATUS,
+                         base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr);
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    command_queue_.push_back(std::move(command));
+    command_status_callbacks.push_back(std::move(on_status));
+    if (command_promise_ != nullptr) {
+      command_promise_->set_value(command_queue_.size());
+      command_promise_.reset();
+    }
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+    command_queue_.push_back(std::move(command));
+    command_complete_callbacks.push_back(std::move(on_complete));
+    if (command_promise_ != nullptr) {
+      command_promise_->set_value(command_queue_.size());
+      command_promise_.reset();
+    }
+  }
+
+  std::future<size_t> GetCommandFuture() {
+    ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time");
+    command_promise_ = std::make_unique<std::promise<size_t>>();
+    return command_promise_->get_future();
+  }
+
+  std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
+    ASSERT(!command_queue_.empty());
+    auto last = std::move(command_queue_.front());
+    command_queue_.pop_front();
+    return last;
+  }
+
+  ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+    auto packet_view = GetPacketView(GetLastCommand());
+    CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+    ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+    ASSERT(command.IsValid());
+    EXPECT_EQ(command.GetOpCode(), op_code);
+
+    return command;
+  }
+
+  void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+                            os::Handler* handler) override {
+    registered_events_[event_code] = event_handler;
+  }
+
+  void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+                              os::Handler* handler) override {
+    registered_le_events_[subevent_code] = event_handler;
+  }
+
+  void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    ASSERT_TRUE(event.IsValid());
+    EventCode event_code = event.GetEventCode();
+    ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code);
+    registered_events_[event_code].Run(event);
+  }
+
+  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+    ASSERT_TRUE(meta_event_view.IsValid());
+    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+    ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end())
+        << SubeventCodeText(subevent_code);
+    registered_le_events_[subevent_code].Run(meta_event_view);
+  }
+
+  void CommandCompleteCallback(EventPacketView event) {
+    CommandCompleteView complete_view = CommandCompleteView::Create(event);
+    ASSERT(complete_view.IsValid());
+    std::move(command_complete_callbacks.front()).Run(complete_view);
+    command_complete_callbacks.pop_front();
+  }
+
+  void CommandStatusCallback(EventPacketView event) {
+    CommandStatusView status_view = CommandStatusView::Create(event);
+    ASSERT(status_view.IsValid());
+    std::move(command_status_callbacks.front()).Run(status_view);
+    command_status_callbacks.pop_front();
+  }
+
+  void ListDependencies(ModuleList* list) override {}
+  void Start() override {}
+  void Stop() override {}
+
+ private:
+  std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+  std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+  std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
+  std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks;
+
+  std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+  mutable std::mutex mutex_;
+  std::unique_ptr<std::promise<size_t>> command_promise_{};
+};
+
+class LeAdvertisingManagerTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    test_hci_layer_ = new TestHciLayer;  // Ownership is transferred to registry
+    test_controller_ = new TestController;
+    test_controller_->AddSupported(param_opcode_);
+    fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+    fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
+    client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+    ASSERT_NE(client_handler_, nullptr);
+    test_controller_->num_advertisers = 1;
+    fake_registry_.Start<LeAdvertisingManager>(&thread_);
+    le_advertising_manager_ =
+        static_cast<LeAdvertisingManager*>(fake_registry_.GetModuleUnderTest(&LeAdvertisingManager::Factory));
+  }
+
+  void TearDown() override {
+    fake_registry_.SynchronizeModuleHandler(&LeAdvertisingManager::Factory, std::chrono::milliseconds(20));
+    fake_registry_.StopAll();
+  }
+
+  TestModuleRegistry fake_registry_;
+  TestHciLayer* test_hci_layer_ = nullptr;
+  TestController* test_controller_ = nullptr;
+  os::Thread& thread_ = fake_registry_.GetTestThread();
+  LeAdvertisingManager* le_advertising_manager_ = nullptr;
+  os::Handler* client_handler_ = nullptr;
+
+  const common::Callback<void(Address, AddressType)> scan_callback =
+      common::Bind(&LeAdvertisingManagerTest::on_scan, common::Unretained(this));
+  const common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback =
+      common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this));
+
+  std::future<Address> GetOnScanPromise() {
+    ASSERT_LOG(address_promise_ == nullptr, "Promises promises ... Only one at a time");
+    address_promise_ = std::make_unique<std::promise<Address>>();
+    return address_promise_->get_future();
+  }
+  void on_scan(Address address, AddressType address_type) {
+    if (address_promise_ == nullptr) {
+      return;
+    }
+    address_promise_->set_value(address);
+    address_promise_.reset();
+  }
+
+  std::future<ErrorCode> GetSetTerminatedPromise() {
+    ASSERT_LOG(set_terminated_promise_ == nullptr, "Promises promises ... Only one at a time");
+    set_terminated_promise_ = std::make_unique<std::promise<ErrorCode>>();
+    return set_terminated_promise_->get_future();
+  }
+  void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) {
+    if (set_terminated_promise_ != nullptr) {
+      return;
+    }
+    set_terminated_promise_->set_value(error_code);
+    set_terminated_promise_.reset();
+  }
+
+  std::unique_ptr<std::promise<Address>> address_promise_{};
+  std::unique_ptr<std::promise<ErrorCode>> set_terminated_promise_{};
+
+  OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
+};
+
+class LeAndroidHciAdvertisingManagerTest : public LeAdvertisingManagerTest {
+ protected:
+  void SetUp() override {
+    param_opcode_ = OpCode::LE_MULTI_ADVT;
+    LeAdvertisingManagerTest::SetUp();
+    test_controller_->num_advertisers = 3;
+  }
+};
+
+class LeExtendedAdvertisingManagerTest : public LeAdvertisingManagerTest {
+ protected:
+  void SetUp() override {
+    param_opcode_ = OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS;
+    LeAdvertisingManagerTest::SetUp();
+    test_controller_->num_advertisers = 5;
+  }
+};
+
+TEST_F(LeAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeAndroidHciAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeExtendedAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeAdvertisingManagerTest, create_advertiser_test) {
+  AdvertisingConfig advertising_config{};
+  advertising_config.event_type = AdvertisingEventType::ADV_IND;
+  advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+  std::vector<GapData> gap_data{};
+  GapData data_item{};
+  data_item.data_type_ = GapDataType::FLAGS;
+  data_item.data_ = {0x34};
+  gap_data.push_back(data_item);
+  data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+  data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+  gap_data.push_back(data_item);
+  advertising_config.advertisement = gap_data;
+  advertising_config.scan_response = gap_data;
+
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback,
+                                                      client_handler_);
+  ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
+  std::vector<OpCode> adv_opcodes = {
+      OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS,     OpCode::LE_SET_SCAN_RESPONSE_DATA,
+      OpCode::LE_SET_ADVERTISING_DATA,       OpCode::LE_SET_ADVERTISING_ENABLE,
+  };
+  auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  ASSERT_NE(std::future_status::timeout, result);
+  size_t num_commands = next_command_future.get();
+  for (size_t i = 0; i < adv_opcodes.size(); i++) {
+    auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]);
+    std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
+    test_hci_layer_->IncomingEvent(
+        CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
+    if (i < adv_opcodes.size() - 1 && --num_commands == 1) {
+      next_command_future = test_hci_layer_->GetCommandFuture();
+      result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+      ASSERT_NE(std::future_status::timeout, result);
+      num_commands = next_command_future.get();
+    }
+  }
+}
+
+TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) {
+  AdvertisingConfig advertising_config{};
+  advertising_config.event_type = AdvertisingEventType::ADV_IND;
+  advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+  std::vector<GapData> gap_data{};
+  GapData data_item{};
+  data_item.data_type_ = GapDataType::FLAGS;
+  data_item.data_ = {0x34};
+  gap_data.push_back(data_item);
+  data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+  data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+  gap_data.push_back(data_item);
+  advertising_config.advertisement = gap_data;
+  advertising_config.scan_response = gap_data;
+
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback,
+                                                      client_handler_);
+  ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
+  std::vector<SubOcf> sub_ocf = {
+      SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE,
+  };
+  auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  ASSERT_NE(std::future_status::timeout, result);
+  size_t num_commands = next_command_future.get();
+  for (size_t i = 0; i < sub_ocf.size(); i++) {
+    auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT);
+    std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])};
+    test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT,
+                                                                  std::make_unique<RawBuilder>(success_vector)));
+    if (i < sub_ocf.size() - 1 && --num_commands == 1) {
+      next_command_future = test_hci_layer_->GetCommandFuture();
+      result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+      ASSERT_NE(std::future_status::timeout, result);
+      num_commands = next_command_future.get();
+    }
+  }
+}
+
+}  // namespace
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/le_device.h b/gd/hci/le_device.h
new file mode 100644
index 0000000..35a620b
--- /dev/null
+++ b/gd/hci/le_device.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ *  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 "hci/device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * TODO(optedoblivion): Build out AddressType getter/setter
+ */
+// enum AddressType {};
+
+/**
+ * A device representing a LE device.
+ *
+ * <p>This can be a LE only or a piece of a DUAL MODE device.
+ *
+ * <p>LE specific public address logic goes here.
+ */
+class LeDevice : public Device {
+ public:
+  void SetPublicAddress(Address public_address) {
+    public_address_ = public_address;
+  }
+
+  Address GetPublicAddress() {
+    return public_address_;
+  }
+
+  void SetIrk(uint8_t irk) {
+    irk_ = irk;
+    // TODO(optedoblivion): Set derived Address
+  }
+
+  uint8_t GetIrk() {
+    return irk_;
+  }
+
+ protected:
+  friend class DeviceDatabase;
+  // TODO(optedoblivion): How to set public address.  Do I set it when no IRK is known?
+  // Right now my thought is to do this:
+  // 1. Construct LeDevice with address of all 0s
+  // 2. IF NO IRK AND NO PRIVATE ADDRESS: (i.e. nothing in disk cache)
+  //  a. Hopefully pairing will happen
+  //  b. Pending successful pairing get the IRK and Private Address
+  //  c. Set Both to device.
+  //  (d). If available set IRK to the controller (later iteration)
+  // [#3 should indicate we have a bug]
+  // 3. IF YES IRK AND NO PRIVATE ADDRESS: (Partial Disk Cache Information)
+  //  a. Set IRK
+  //  b. Generate Private Address
+  //  c. Set Private Address to device
+  //  (d). If available set IRK to the controller (later iteration)
+  // 4. IF YES IRK AND YES PRIVATE ADDRESS: (i.e. Disk cache hit)
+  //  a. Construct with private address
+  //  b. Set IRK
+  //  (c). If available set IRK to the controller (later iteration)
+  // 5. IF NO IRK AND YES PRIVATE ADDRESS (we have a bug)
+  //  a1. -Construct with private address-
+  //  b. -Indicate we need to repair or query for IRK?-
+  //
+  //  or
+  //
+  //  a2. Don't use class
+  explicit LeDevice(Address address) : Device(address, DeviceType::LE), public_address_(), irk_(0) {}
+
+ private:
+  Address public_address_;
+  uint8_t irk_;
+};
+
+}  // namespace bluetooth::hci
diff --git a/gd/hci/le_report.h b/gd/hci/le_report.h
new file mode 100644
index 0000000..7dc075f
--- /dev/null
+++ b/gd/hci/le_report.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <memory>
+
+#include "hci/hci_packets.h"
+
+namespace bluetooth::hci {
+
+class LeReport {
+ public:
+  explicit LeReport(const LeAdvertisingReport& advertisement)
+      : report_type_(ReportType::ADVERTISING_EVENT), advertising_event_type_(advertisement.event_type_),
+        address_(advertisement.address_), address_type_(advertisement.address_type_), rssi_(advertisement.rssi_),
+        gap_data_(advertisement.advertising_data_) {}
+  explicit LeReport(const LeDirectedAdvertisingReport& advertisement)
+      : report_type_(ReportType::DIRECTED_ADVERTISING_EVENT), address_(advertisement.address_),
+        rssi_(advertisement.rssi_) {}
+  explicit LeReport(const LeExtendedAdvertisingReport& advertisement)
+      : report_type_(ReportType::EXTENDED_ADVERTISING_EVENT), address_(advertisement.address_),
+        rssi_(advertisement.rssi_), gap_data_(advertisement.advertising_data_) {}
+  virtual ~LeReport() = default;
+
+  enum class ReportType {
+    ADVERTISING_EVENT = 1,
+    DIRECTED_ADVERTISING_EVENT = 2,
+    EXTENDED_ADVERTISING_EVENT = 3,
+  };
+  const ReportType report_type_;
+
+  ReportType GetReportType() const {
+    return report_type_;
+  }
+
+  // Advertising Event
+  const AdvertisingEventType advertising_event_type_{};
+  const Address address_{};
+  const AddressType address_type_{};
+  const uint8_t rssi_;
+  const std::vector<GapData> gap_data_{};
+};
+
+class DirectedLeReport : public LeReport {
+ public:
+  explicit DirectedLeReport(const LeDirectedAdvertisingReport& advertisement)
+      : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}
+  explicit DirectedLeReport(const LeExtendedAdvertisingReport& advertisement)
+      : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}
+
+  const DirectAdvertisingAddressType direct_address_type_{};
+};
+
+class ExtendedLeReport : public DirectedLeReport {
+ public:
+  explicit ExtendedLeReport(const LeExtendedAdvertisingReport& advertisement)
+      : DirectedLeReport(advertisement), connectable_(advertisement.connectable_), scannable_(advertisement.scannable_),
+        directed_(advertisement.directed_), scan_response_(advertisement.scan_response_),
+        complete_(advertisement.data_status_ == DataStatus::COMPLETE),
+        truncated_(advertisement.data_status_ == DataStatus::TRUNCATED) {}
+
+  // Extended
+  bool connectable_;
+  bool scannable_;
+  bool directed_;
+  bool scan_response_;
+  bool complete_;
+  bool truncated_;
+};
+}  // namespace bluetooth::hci
\ No newline at end of file
diff --git a/gd/hci/le_scanning_interface.h b/gd/hci/le_scanning_interface.h
new file mode 100644
index 0000000..97a6766
--- /dev/null
+++ b/gd/hci/le_scanning_interface.h
@@ -0,0 +1,50 @@
+/*
+ * 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 "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeScanningInterface {
+ public:
+  LeScanningInterface() = default;
+  virtual ~LeScanningInterface() = default;
+  DISALLOW_COPY_AND_ASSIGN(LeScanningInterface);
+
+  virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+  static constexpr hci::SubeventCode LeScanningEvents[] = {
+      hci::SubeventCode::SCAN_TIMEOUT,
+      hci::SubeventCode::ADVERTISING_REPORT,
+      hci::SubeventCode::DIRECTED_ADVERTISING_REPORT,
+      hci::SubeventCode::EXTENDED_ADVERTISING_REPORT,
+      hci::SubeventCode::PERIODIC_ADVERTISING_REPORT,
+      hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED,
+      hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST,
+  };
+};
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/le_scanning_manager.cc b/gd/hci/le_scanning_manager.cc
new file mode 100644
index 0000000..0b1bb62
--- /dev/null
+++ b/gd/hci/le_scanning_manager.cc
@@ -0,0 +1,251 @@
+/*
+ * 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 <memory>
+#include <mutex>
+#include <set>
+
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "hci/le_scanning_interface.h"
+#include "hci/le_scanning_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hci {
+
+const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); });
+
+enum class ScanApiType {
+  LE_4_0 = 1,
+  ANDROID_HCI = 2,
+  LE_5_0 = 3,
+};
+
+struct LeScanningManager::impl {
+  impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {}
+
+  void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
+    module_handler_ = handler;
+    hci_layer_ = hci_layer;
+    controller_ = controller;
+    le_scanning_interface_ = hci_layer_->GetLeScanningInterface(
+        common::Bind(&LeScanningManager::impl::handle_scan_results, common::Unretained(this)), module_handler_);
+    if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) {
+      api_type_ = ScanApiType::LE_5_0;
+    } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) {
+      api_type_ = ScanApiType::ANDROID_HCI;
+    } else {
+      api_type_ = ScanApiType::LE_4_0;
+    }
+    configure_scan();
+  }
+
+  void handle_scan_results(LeMetaEventView event) {
+    switch (event.GetSubeventCode()) {
+      case hci::SubeventCode::ADVERTISING_REPORT:
+        handle_advertising_report<LeAdvertisingReportView, LeAdvertisingReport, LeReport>(
+            LeAdvertisingReportView::Create(event));
+        break;
+      case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
+        handle_advertising_report<LeDirectedAdvertisingReportView, LeDirectedAdvertisingReport, DirectedLeReport>(
+            LeDirectedAdvertisingReportView::Create(event));
+        break;
+      case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
+        handle_advertising_report<LeExtendedAdvertisingReportView, LeExtendedAdvertisingReport, ExtendedLeReport>(
+            LeExtendedAdvertisingReportView::Create(event));
+        break;
+      case hci::SubeventCode::SCAN_TIMEOUT:
+        if (registered_callback_ != nullptr) {
+          registered_callback_->handler->Post(
+              common::BindOnce(&LeScanningManagerCallbacks::on_timeout, common::Unretained(registered_callback_)));
+          registered_callback_ = nullptr;
+        }
+        break;
+      default:
+        LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
+    }
+  }
+
+  template <class EventType, class ReportStructType, class ReportType>
+  void handle_advertising_report(EventType event_view) {
+    if (registered_callback_ == nullptr) {
+      LOG_INFO("Dropping advertising event (no registered handler)");
+      return;
+    }
+    if (!event_view.IsValid()) {
+      LOG_INFO("Dropping invalid advertising event");
+      return;
+    }
+    std::vector<ReportStructType> report_vector = event_view.GetAdvertisingReports();
+    if (report_vector.empty()) {
+      LOG_INFO("Zero results in advertising event");
+      return;
+    }
+    std::vector<std::shared_ptr<LeReport>> param;
+    param.reserve(report_vector.size());
+    for (const ReportStructType& report : report_vector) {
+      param.push_back(std::shared_ptr<LeReport>(static_cast<LeReport*>(new ReportType(report))));
+    }
+    registered_callback_->handler->Post(common::BindOnce(&LeScanningManagerCallbacks::on_advertisements,
+                                                         common::Unretained(registered_callback_), param));
+  }
+
+  void configure_scan() {
+    switch (api_type_) {
+      case ScanApiType::LE_5_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetExtendedScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_,
+                                                            own_address_type_, filter_policy_),
+            common::BindOnce(impl::check_status), module_handler_);
+        break;
+      case ScanApiType::ANDROID_HCI:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
+                                                     filter_policy_),
+            common::BindOnce(impl::check_status), module_handler_);
+
+        break;
+      case ScanApiType::LE_4_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
+                                                    filter_policy_),
+            common::BindOnce(impl::check_status), module_handler_);
+        break;
+    }
+  }
+
+  void start_scan(LeScanningManagerCallbacks* le_scanning_manager_callbacks) {
+    registered_callback_ = le_scanning_manager_callbacks;
+    switch (api_type_) {
+      case ScanApiType::LE_5_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetExtendedScanEnableBuilder::Create(Enable::ENABLED,
+                                                        FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
+            common::BindOnce(impl::check_status), module_handler_);
+        break;
+      case ScanApiType::ANDROID_HCI:
+      case ScanApiType::LE_4_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */),
+            common::BindOnce(impl::check_status), module_handler_);
+        break;
+    }
+  }
+
+  void stop_scan(common::Callback<void()> on_stopped) {
+    if (registered_callback_ == nullptr) {
+      return;
+    }
+    registered_callback_->handler->Post(std::move(on_stopped));
+    switch (api_type_) {
+      case ScanApiType::LE_5_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetExtendedScanEnableBuilder::Create(Enable::DISABLED,
+                                                        FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
+            common::BindOnce(impl::check_status), module_handler_);
+        registered_callback_->handler = nullptr;
+        break;
+      case ScanApiType::ANDROID_HCI:
+      case ScanApiType::LE_4_0:
+        le_scanning_interface_->EnqueueCommand(
+            hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */),
+            common::BindOnce(impl::check_status), module_handler_);
+        registered_callback_->handler = nullptr;
+        break;
+    }
+  }
+
+  ScanApiType api_type_;
+
+  LeScanningManagerCallbacks* registered_callback_;
+  Module* module_;
+  os::Handler* module_handler_;
+  hci::HciLayer* hci_layer_;
+  hci::Controller* controller_;
+  hci::LeScanningInterface* le_scanning_interface_;
+
+  uint32_t interval_ms_{1000};
+  uint16_t window_ms_{1000};
+  AddressType own_address_type_{AddressType::PUBLIC_DEVICE_ADDRESS};
+  LeSetScanningFilterPolicy filter_policy_{LeSetScanningFilterPolicy::ACCEPT_ALL};
+
+  static void check_status(CommandCompleteView view) {
+    switch (view.GetCommandOpCode()) {
+      case (OpCode::LE_SET_SCAN_ENABLE): {
+        auto status_view = LeSetScanEnableCompleteView::Create(view);
+        ASSERT(status_view.IsValid());
+        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+      } break;
+      case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): {
+        auto status_view = LeSetExtendedScanEnableCompleteView::Create(view);
+        ASSERT(status_view.IsValid());
+        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+      } break;
+      case (OpCode::LE_SET_SCAN_PARAMETERS): {
+        auto status_view = LeSetScanParametersCompleteView::Create(view);
+        ASSERT(status_view.IsValid());
+        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+      } break;
+      case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
+        auto status_view = LeExtendedScanParamsCompleteView::Create(view);
+        ASSERT(status_view.IsValid());
+        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+      } break;
+      case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
+        auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
+        ASSERT(status_view.IsValid());
+        ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+      } break;
+      default:
+        LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
+    }
+  }
+};
+
+LeScanningManager::LeScanningManager() {
+  pimpl_ = std::make_unique<impl>(this);
+}
+
+void LeScanningManager::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+  list->add<hci::Controller>();
+}
+
+void LeScanningManager::Start() {
+  pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
+}
+
+void LeScanningManager::Stop() {
+  pimpl_.reset();
+}
+
+std::string LeScanningManager::ToString() const {
+  return "Le Scanning Manager";
+}
+
+void LeScanningManager::StartScan(LeScanningManagerCallbacks* callbacks) {
+  GetHandler()->Post(common::Bind(&impl::start_scan, common::Unretained(pimpl_.get()), callbacks));
+}
+
+void LeScanningManager::StopScan(common::Callback<void()> on_stopped) {
+  GetHandler()->Post(common::Bind(&impl::stop_scan, common::Unretained(pimpl_.get()), on_stopped));
+}
+
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_scanning_manager.h b/gd/hci/le_scanning_manager.h
new file mode 100644
index 0000000..b8f30d9
--- /dev/null
+++ b/gd/hci/le_scanning_manager.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <memory>
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "hci/le_report.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeScanningManagerCallbacks {
+ public:
+  virtual ~LeScanningManagerCallbacks() = default;
+  virtual void on_advertisements(std::vector<std::shared_ptr<LeReport>>) = 0;
+  virtual void on_timeout() = 0;
+  os::Handler* handler;
+};
+
+class LeScanningManager : public bluetooth::Module {
+ public:
+  LeScanningManager();
+
+  void StartScan(LeScanningManagerCallbacks* callbacks);
+
+  void StopScan(common::Callback<void()> on_stopped);
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+
+  void Start() override;
+
+  void Stop() override;
+
+  std::string ToString() const override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(LeScanningManager);
+};
+
+}  // namespace hci
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_scanning_manager_test.cc b/gd/hci/le_scanning_manager_test.cc
new file mode 100644
index 0000000..e5e461e
--- /dev/null
+++ b/gd/hci/le_scanning_manager_test.cc
@@ -0,0 +1,336 @@
+/*
+ * 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 "hci/le_scanning_manager.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestController : public Controller {
+ public:
+  bool IsSupported(OpCode op_code) const override {
+    return supported_opcodes_.count(op_code) == 1;
+  }
+
+  void AddSupported(OpCode op_code) {
+    supported_opcodes_.insert(op_code);
+  }
+
+ protected:
+  void Start() override {}
+  void Stop() override {}
+  void ListDependencies(ModuleList* list) override {}
+
+ private:
+  std::set<OpCode> supported_opcodes_{};
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+  TestHciLayer() {
+    RegisterEventHandler(EventCode::COMMAND_COMPLETE,
+                         base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr);
+    RegisterEventHandler(EventCode::COMMAND_STATUS,
+                         base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr);
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+    command_queue_.push(std::move(command));
+    command_status_callbacks.push_front(std::move(on_status));
+    if (command_promise_ != nullptr) {
+      command_promise_->set_value();
+      command_promise_.reset();
+    }
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+    command_queue_.push(std::move(command));
+    command_complete_callbacks.push_front(std::move(on_complete));
+    if (command_promise_ != nullptr) {
+      command_promise_->set_value();
+      command_promise_.reset();
+    }
+  }
+
+  std::future<void> GetCommandFuture() {
+    ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time");
+    command_promise_ = std::make_unique<std::promise<void>>();
+    return command_promise_->get_future();
+  }
+
+  std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
+    ASSERT(!command_queue_.empty());
+    auto last = std::move(command_queue_.front());
+    command_queue_.pop();
+    return last;
+  }
+
+  ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+    auto packet_view = GetPacketView(GetLastCommand());
+    CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+    ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+    ASSERT(command.IsValid());
+    EXPECT_EQ(command.GetOpCode(), op_code);
+
+    return command;
+  }
+
+  void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+                            os::Handler* handler) override {
+    registered_events_[event_code] = event_handler;
+  }
+
+  void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+                              os::Handler* handler) override {
+    registered_le_events_[subevent_code] = event_handler;
+  }
+
+  void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    ASSERT_TRUE(event.IsValid());
+    EventCode event_code = event.GetEventCode();
+    ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code);
+    registered_events_[event_code].Run(event);
+  }
+
+  void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+    ASSERT_TRUE(meta_event_view.IsValid());
+    SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+    ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end())
+        << SubeventCodeText(subevent_code);
+    registered_le_events_[subevent_code].Run(meta_event_view);
+  }
+
+  void CommandCompleteCallback(EventPacketView event) {
+    CommandCompleteView complete_view = CommandCompleteView::Create(event);
+    ASSERT(complete_view.IsValid());
+    std::move(command_complete_callbacks.front()).Run(complete_view);
+    command_complete_callbacks.pop_front();
+  }
+
+  void CommandStatusCallback(EventPacketView event) {
+    CommandStatusView status_view = CommandStatusView::Create(event);
+    ASSERT(status_view.IsValid());
+    std::move(command_status_callbacks.front()).Run(status_view);
+    command_status_callbacks.pop_front();
+  }
+
+  void ListDependencies(ModuleList* list) override {}
+  void Start() override {}
+  void Stop() override {}
+
+ private:
+  std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+  std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+  std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
+  std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks;
+
+  std::queue<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+  mutable std::mutex mutex_;
+  std::unique_ptr<std::promise<void>> command_promise_{};
+};
+
+class LeScanningManagerTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    test_hci_layer_ = new TestHciLayer;  // Ownership is transferred to registry
+    test_controller_ = new TestController;
+    test_controller_->AddSupported(param_opcode_);
+    fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+    fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
+    client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+    ASSERT_NE(client_handler_, nullptr);
+    mock_callbacks_.handler = client_handler_;
+    std::future<void> config_future = test_hci_layer_->GetCommandFuture();
+    fake_registry_.Start<LeScanningManager>(&thread_);
+    le_scanning_manager =
+        static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory));
+    config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000)));
+    HandleConfiguration();
+  }
+
+  void TearDown() override {
+    fake_registry_.SynchronizeModuleHandler(&LeScanningManager::Factory, std::chrono::milliseconds(20));
+    fake_registry_.StopAll();
+  }
+
+  virtual void HandleConfiguration() {
+    auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_SCAN_PARAMETERS);
+    test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+  }
+
+  TestModuleRegistry fake_registry_;
+  TestHciLayer* test_hci_layer_ = nullptr;
+  TestController* test_controller_ = nullptr;
+  os::Thread& thread_ = fake_registry_.GetTestThread();
+  LeScanningManager* le_scanning_manager = nullptr;
+  os::Handler* client_handler_ = nullptr;
+
+  class MockLeScanningManagerCallbacks : public LeScanningManagerCallbacks {
+   public:
+    MOCK_METHOD(void, on_advertisements, (std::vector<std::shared_ptr<LeReport>>), (override));
+    MOCK_METHOD(void, on_timeout, (), (override));
+  } mock_callbacks_;
+
+  OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
+};
+
+class LeAndroidHciScanningManagerTest : public LeScanningManagerTest {
+ protected:
+  void SetUp() override {
+    param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS;
+    LeScanningManagerTest::SetUp();
+  }
+
+  void HandleConfiguration() override {
+    auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_EXTENDED_SCAN_PARAMS);
+    test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+  }
+};
+
+class LeExtendedScanningManagerTest : public LeScanningManagerTest {
+ protected:
+  void SetUp() override {
+    param_opcode_ = OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS;
+    LeScanningManagerTest::SetUp();
+  }
+
+  void HandleConfiguration() override {
+    auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS);
+    test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+  }
+};
+
+TEST_F(LeScanningManagerTest, startup_teardown) {}
+
+TEST_F(LeScanningManagerTest, start_scan_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  le_scanning_manager->StartScan(&mock_callbacks_);
+
+  next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+  LeAdvertisingReport report{};
+  report.event_type_ = AdvertisingEventType::ADV_IND;
+  report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS;
+  Address::FromString("12:34:56:78:9a:bc", report.address_);
+  std::vector<GapData> gap_data{};
+  GapData data_item{};
+  data_item.data_type_ = GapDataType::FLAGS;
+  data_item.data_ = {0x34};
+  gap_data.push_back(data_item);
+  data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+  data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+  gap_data.push_back(data_item);
+  report.advertising_data_ = gap_data;
+
+  EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
+}
+
+TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  le_scanning_manager->StartScan(&mock_callbacks_);
+
+  next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+  LeAdvertisingReport report{};
+  report.event_type_ = AdvertisingEventType::ADV_IND;
+  report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS;
+  Address::FromString("12:34:56:78:9a:bc", report.address_);
+  std::vector<GapData> gap_data{};
+  GapData data_item{};
+  data_item.data_type_ = GapDataType::FLAGS;
+  data_item.data_ = {0x34};
+  gap_data.push_back(data_item);
+  data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+  data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+  gap_data.push_back(data_item);
+  report.advertising_data_ = gap_data;
+
+  EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
+}
+
+TEST_F(LeExtendedScanningManagerTest, start_scan_test) {
+  auto next_command_future = test_hci_layer_->GetCommandFuture();
+  le_scanning_manager->StartScan(&mock_callbacks_);
+
+  next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+  auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_ENABLE);
+
+  test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+  LeExtendedAdvertisingReport report{};
+  report.connectable_ = 1;
+  report.scannable_ = 1;
+  report.address_type_ = DirectAdvertisingAddressType::PUBLIC_DEVICE_ADDRESS;
+  Address::FromString("12:34:56:78:9a:bc", report.address_);
+  std::vector<GapData> gap_data{};
+  GapData data_item{};
+  data_item.data_type_ = GapDataType::FLAGS;
+  data_item.data_ = {0x34};
+  gap_data.push_back(data_item);
+  data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+  data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+  gap_data.push_back(data_item);
+  report.advertising_data_ = gap_data;
+
+  EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+  test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report}));
+}
+
+}  // namespace
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/le_security_interface.h b/gd/hci/le_security_interface.h
new file mode 100644
index 0000000..13c3ef3
--- /dev/null
+++ b/gd/hci/le_security_interface.h
@@ -0,0 +1,46 @@
+/*
+ * 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 "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeSecurityInterface {
+ public:
+  LeSecurityInterface() = default;
+  virtual ~LeSecurityInterface() = default;
+  DISALLOW_COPY_AND_ASSIGN(LeSecurityInterface);
+
+  virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+  virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+  static constexpr hci::SubeventCode LeSecurityEvents[] = {
+      hci::SubeventCode::LONG_TERM_KEY_REQUEST,
+      hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE,
+      hci::SubeventCode::GENERATE_DHKEY_COMPLETE,
+  };
+};
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/hci/security_interface.h b/gd/hci/security_interface.h
new file mode 100644
index 0000000..ea15aa0
--- /dev/null
+++ b/gd/hci/security_interface.h
@@ -0,0 +1,50 @@
+/*
+ * 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 "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class SecurityInterface {
+ public:
+  SecurityInterface() = default;
+  virtual ~SecurityInterface() = default;
+  DISALLOW_COPY_AND_ASSIGN(SecurityInterface);
+
+  virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+  virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+                              common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+  static constexpr hci::EventCode SecurityEvents[] = {
+      hci::EventCode::ENCRYPTION_CHANGE,         hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE,
+      hci::EventCode::MASTER_LINK_KEY_COMPLETE,  hci::EventCode::RETURN_LINK_KEYS,
+      hci::EventCode::PIN_CODE_REQUEST,          hci::EventCode::LINK_KEY_REQUEST,
+      hci::EventCode::LINK_KEY_NOTIFICATION,     hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE,
+      hci::EventCode::IO_CAPABILITY_REQUEST,     hci::EventCode::IO_CAPABILITY_RESPONSE,
+      hci::EventCode::REMOTE_OOB_DATA_REQUEST,   hci::EventCode::SIMPLE_PAIRING_COMPLETE,
+      hci::EventCode::USER_PASSKEY_NOTIFICATION, hci::EventCode::KEYPRESS_NOTIFICATION,
+      hci::EventCode::USER_CONFIRMATION_REQUEST, hci::EventCode::USER_PASSKEY_REQUEST,
+  };
+};
+}  // namespace hci
+}  // namespace bluetooth
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
index d061305..3d65446 100644
--- a/gd/l2cap/Android.bp
+++ b/gd/l2cap/Android.bp
@@ -1,18 +1,57 @@
 filegroup {
     name: "BluetoothL2capSources",
     srcs: [
-        "l2cap_layer.cc",
-        "classic_fixed_channel.cc",
-        "classic_fixed_channel_manager.cc",
-        "classic_fixed_channel_service.cc",
+        "fcs.cc",
+        "classic/dynamic_channel.cc",
+        "classic/dynamic_channel_manager.cc",
+        "classic/dynamic_channel_service.cc",
+        "classic/fixed_channel.cc",
+        "classic/fixed_channel_manager.cc",
+        "classic/fixed_channel_service.cc",
+        "classic/internal/dynamic_channel_allocator.cc",
+        "classic/internal/dynamic_channel_impl.cc",
+        "classic/internal/dynamic_channel_service_manager_impl.cc",
+        "classic/internal/fixed_channel_impl.cc",
+        "classic/internal/fixed_channel_service_manager_impl.cc",
+        "classic/internal/link.cc",
+        "classic/internal/link_manager.cc",
+        "classic/internal/signalling_manager.cc",
+        "classic/l2cap_classic_module.cc",
+        "internal/basic_mode_channel_data_controller.cc",
+        "internal/enhanced_retransmission_mode_channel_data_controller.cc",
+        "internal/receiver.cc",
+        "internal/scheduler_fifo.cc",
+        "internal/sender.cc",
+        "le/internal/fixed_channel_impl.cc",
+        "le/internal/fixed_channel_service_manager_impl.cc",
+        "le/internal/link_manager.cc",
+        "le/fixed_channel.cc",
+        "le/fixed_channel_manager.cc",
+        "le/fixed_channel_service.cc",
+        "le/l2cap_le_module.cc",
     ],
 }
 
 filegroup {
     name: "BluetoothL2capTestSources",
     srcs: [
+        "classic/internal/dynamic_channel_allocator_test.cc",
+        "classic/internal/dynamic_channel_impl_test.cc",
+        "classic/internal/dynamic_channel_service_manager_test.cc",
+        "classic/internal/fixed_channel_impl_test.cc",
+        "classic/internal/fixed_channel_service_manager_test.cc",
+        "classic/internal/link_manager_test.cc",
+        "classic/internal/signalling_manager_test.cc",
+        "internal/basic_mode_channel_data_controller_test.cc",
+        "internal/enhanced_retransmission_mode_channel_data_controller_test.cc",
+        "internal/fixed_channel_allocator_test.cc",
+        "internal/receiver_test.cc",
+        "internal/scheduler_fifo_test.cc",
+        "internal/sender_test.cc",
         "l2cap_packet_test.cc",
-        "fcs.cc",
+        "le/internal/fixed_channel_impl_test.cc",
+        "le/internal/fixed_channel_service_manager_test.cc",
+        "le/internal/link_manager_test.cc",
         "signal_id_test.cc",
     ],
 }
@@ -20,13 +59,21 @@
 filegroup {
     name: "BluetoothFacade_l2cap_layer",
     srcs: [
-        "facade.cc",
+        "classic/facade.cc",
     ],
 }
 
 filegroup {
     name: "BluetoothCertSource_l2cap_layer",
     srcs: [
-        "cert/cert.cc",
+        "classic/cert/cert.cc",
     ],
-}
\ No newline at end of file
+}
+
+filegroup {
+    name: "BluetoothL2capFuzzTestSources",
+    srcs: [
+        "classic/internal/dynamic_channel_allocator_fuzz_test.cc",
+        "l2cap_packet_fuzz_test.cc",
+    ],
+}
diff --git a/gd/l2cap/cert/api.proto b/gd/l2cap/cert/api.proto
deleted file mode 100644
index cba982b..0000000
--- a/gd/l2cap/cert/api.proto
+++ /dev/null
@@ -1,10 +0,0 @@
-syntax = "proto3";
-
-package bluetooth.l2cap.cert;
-
-import "google/protobuf/empty.proto";
-import "facade/common.proto";
-
-service L2capModuleCert {
-  rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-}
diff --git a/gd/l2cap/cert/cert.cc b/gd/l2cap/cert/cert.cc
deleted file mode 100644
index 6fd06e2..0000000
--- a/gd/l2cap/cert/cert.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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/cert/cert.h"
-
-#include <cstdint>
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-
-#include "common/blocking_queue.h"
-#include "grpc/grpc_event_stream.h"
-#include "l2cap/cert/api.grpc.pb.h"
-#include "l2cap/l2cap_layer.h"
-#include "l2cap/l2cap_packets.h"
-#include "os/log.h"
-#include "packet/raw_builder.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-using ::bluetooth::facade::EventStreamRequest;
-using ::bluetooth::packet::RawBuilder;
-
-namespace bluetooth {
-namespace l2cap {
-namespace cert {
-
-using namespace facade;
-
-class L2capModuleCertService : public L2capModuleCert::Service {
- public:
-  L2capModuleCertService(l2cap::L2capLayer* l2cap_layer, ::bluetooth::os::Handler* facade_handler)
-      : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler) {
-    ASSERT(l2cap_layer_ != nullptr);
-    ASSERT(facade_handler_ != nullptr);
-  }
-
-  ::grpc::Status NoOp(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-                      ::google::protobuf::Empty* response) override {
-    return ::grpc::Status::OK;
-  }
-
- private:
-  l2cap::L2capLayer* l2cap_layer_;
-  ::bluetooth::os::Handler* facade_handler_;
-  std::mutex mutex_;
-};
-
-void L2capModuleCertModule::ListDependencies(ModuleList* list) {
-  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
-  list->add<l2cap::L2capLayer>();
-}
-
-void L2capModuleCertModule::Start() {
-  ::bluetooth::grpc::GrpcFacadeModule::Start();
-  service_ = new L2capModuleCertService(GetDependency<l2cap::L2capLayer>(), GetHandler());
-}
-
-void L2capModuleCertModule::Stop() {
-  delete service_;
-  ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* L2capModuleCertModule::GetService() const {
-  return service_;
-}
-
-const ModuleFactory L2capModuleCertModule::Factory =
-    ::bluetooth::ModuleFactory([]() { return new L2capModuleCertModule(); });
-
-}  // namespace cert
-}  // namespace l2cap
-}  // namespace bluetooth
diff --git a/gd/l2cap/cert/simple_l2cap_test.py b/gd/l2cap/cert/simple_l2cap_test.py
deleted file mode 100644
index 3f388f1..0000000
--- a/gd/l2cap/cert/simple_l2cap_test.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python3
-#
-#   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.
-from __future__ import print_function
-
-import os
-import sys
-sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
-
-from cert.gd_base_test import GdBaseTestClass
-from cert import rootservice_pb2 as cert_rootservice_pb2
-from facade import rootservice_pb2 as facade_rootservice_pb2
-from google.protobuf import empty_pb2
-
-class SimpleL2capTest(GdBaseTestClass):
-    def setup_test(self):
-        self.device_under_test = self.gd_devices[0]
-        self.cert_device = self.gd_cert_devices[0]
-        self.device_under_test.rootservice.StartStack(
-            facade_rootservice_pb2.StartStackRequest(
-                module_under_test=facade_rootservice_pb2.BluetoothModule.Value('L2CAP'),
-            )
-        )
-        self.cert_device.rootservice.StartStack(
-            cert_rootservice_pb2.StartStackRequest(
-                module_to_test=cert_rootservice_pb2.BluetoothModule.Value('L2CAP'),
-            )
-        )
-    def teardown_test(self):
-        self.device_under_test.rootservice.StopStack(
-            facade_rootservice_pb2.StopStackRequest()
-        )
-        self.cert_device.rootservice.StopStack(
-            cert_rootservice_pb2.StopStackRequest()
-        )
-
-    def test_no_op(self):
-        if self.device_under_test.l2cap is None:
-            return False
-        self.device_under_test.l2cap.NoOp(empty_pb2.Empty())
-        pass
\ No newline at end of file
diff --git a/gd/l2cap/cid.h b/gd/l2cap/cid.h
index 292131b..729272c 100644
--- a/gd/l2cap/cid.h
+++ b/gd/l2cap/cid.h
@@ -27,7 +27,7 @@
 constexpr Cid kFirstFixedChannel = 1;
 constexpr Cid kLastFixedChannel = 63;
 constexpr Cid kFirstDynamicChannel = kLastFixedChannel + 1;
-constexpr Cid kLastDynamicChannel = (uint16_t)(0xffff + 1);
+constexpr Cid kLastDynamicChannel = (uint16_t)(0xffff);
 
 constexpr Cid kClassicSignallingCid = 1;
 constexpr Cid kConnectionlessCid = 2;
@@ -36,5 +36,7 @@
 constexpr Cid kSmpCid = 6;
 constexpr Cid kSmpBrCid = 7;
 
+constexpr Cid kClassicPairingTriggerCid = kLastFixedChannel - 1;
+
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/cert/api.proto b/gd/l2cap/classic/cert/api.proto
new file mode 100644
index 0000000..c7e68d5
--- /dev/null
+++ b/gd/l2cap/classic/cert/api.proto
@@ -0,0 +1,180 @@
+syntax = "proto3";
+
+package bluetooth.l2cap.classic.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service L2capModuleCert {
+  rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {}
+
+  rpc SetupLink(SetupLinkRequest) returns (SetupLinkResponse) {}
+  rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {}
+
+  rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {}
+  rpc SendConnectionResponse(ConnectionResponse) returns (SendConnectionResponseResult) {}
+
+  rpc SendConfigurationRequest(ConfigurationRequest) returns (SendConfigurationRequestResult) {}
+  rpc SendConfigurationResponse(ConfigurationResponse) returns (SendConfigurationResponseResult) {}
+
+  rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {}
+  rpc SendDisconnectionResponse(DisconnectionResponse) returns (SendDisconnectionResponseResult) {}
+
+  rpc SendInformationRequest(InformationRequest) returns (SendInformationRequestResult) {}
+  rpc SendInformationResponse(InformationResponse) returns (SendInformationResponseResult) {}
+
+  rpc FetchL2capLog(FetchL2capLogRequest) returns (stream FetchL2capLogResponse) {}
+  rpc StopFetchingL2capLog(StopFetchingL2capLogRequest) returns (StopFetchingL2capLogResponse) {}
+}
+
+message L2capPacket {
+  facade.BluetoothAddress remote = 1;
+  uint32 channel = 2;
+  bytes payload = 3;
+}
+
+message DisconnectLinkRequest {
+  facade.BluetoothAddress remote = 1;
+}
+
+message SetupLinkRequest {
+  facade.BluetoothAddress remote = 1;
+}
+
+message SetupLinkResponse {}
+
+message ConnectionRequest {
+  facade.BluetoothAddress remote = 1;
+  uint32 psm = 2;
+  uint32 scid = 3;
+  uint32 signal_id = 4;
+}
+
+message ConnectionResponse {
+  facade.BluetoothAddress remote = 1;
+  uint32 dcid = 2;
+  uint32 scid = 3;
+  uint32 signal_id = 4;
+}
+
+message SendConnectionResponseResult {}
+
+enum ChannelRetransmissionFlowControlMode {
+  BASIC = 0;
+  ERTM = 3;
+  STREAM = 4;
+}
+
+message ChannelRetransmissionFlowControlConfig {
+  ChannelRetransmissionFlowControlMode mode = 1;
+  uint32 tx_window = 2;
+  uint32 max_transmit = 3;
+  uint32 retransmit_timeout = 4;
+  uint32 monitor_timeout = 5;
+  uint32 mps = 6;
+}
+
+message ConfigurationRequest {
+  uint32 dcid = 1;
+  uint32 signal_id = 2;
+  uint32 mtu = 3;
+  ChannelRetransmissionFlowControlConfig retransmission_config = 4;
+  bool fcs = 5;
+}
+
+message SendConfigurationRequestResult {}
+
+message ConfigurationResponse {
+  uint32 scid = 1;
+  uint32 signal_id = 2;
+  uint32 mtu = 3;
+  ChannelRetransmissionFlowControlConfig retransmission_config = 4;
+  bool fcs = 5;
+}
+
+message SendConfigurationResponseResult {}
+
+message DisconnectionRequest {
+  facade.BluetoothAddress remote = 1;
+  uint32 dcid = 2;
+  uint32 scid = 3;
+  uint32 signal_id = 4;
+}
+
+message DisconnectionResponse {
+  facade.BluetoothAddress remote = 1;
+  uint32 dcid = 2;
+  uint32 scid = 3;
+  uint32 signal_id = 4;
+}
+
+message SendDisconnectionResponseResult {}
+
+enum InformationRequestType {
+  CONNECTIONLESS_MTU = 0;
+  EXTENDED_FEATURES = 1;
+  FIXED_CHANNELS = 2;
+}
+
+message InformationRequest {
+  InformationRequestType type = 1;
+  uint32 signal_id = 4;
+}
+
+message SendInformationRequestResult {}
+
+message InformationResponse {
+  InformationRequestType type = 1;
+  uint32 data = 2;
+  uint32 signal_id = 3;
+  uint32 information_value = 4;
+}
+
+message SendInformationResponseResult {}
+
+message FetchL2capLogRequest {}
+
+message CommandReject {
+  uint32 signal_id = 1;
+  uint32 reason = 2;
+}
+
+message EchoRequest {
+  uint32 signal_id = 1;
+  string data = 2;
+}
+message EchoResponse {
+  uint32 signal_id = 1;
+  string data = 2;
+}
+
+message LinkUp {
+  facade.BluetoothAddress remote = 1;
+}
+
+message LinkDown {
+  facade.BluetoothAddress remote = 1;
+}
+
+message FetchL2capLogResponse {
+  oneof response {
+    L2capPacket data_packet = 1;
+    CommandReject command_reject = 2;
+    ConnectionRequest connection_request = 3;
+    ConnectionResponse connection_response = 4;
+    ConfigurationRequest configuration_request = 5;
+    ConfigurationResponse configuration_response = 6;
+    DisconnectionRequest disconnection_request = 7;
+    DisconnectionResponse disconnection_response = 8;
+    EchoRequest echo_request = 9;
+    EchoResponse echo_response = 10;
+    InformationRequest information_request = 11;
+    InformationResponse information_response = 12;
+    LinkUp link_up = 20;
+    LinkDown link_down = 21;
+  }
+}
+
+message StopFetchingL2capLogRequest {}
+
+message StopFetchingL2capLogResponse {}
diff --git a/gd/l2cap/classic/cert/cert.cc b/gd/l2cap/classic/cert/cert.cc
new file mode 100644
index 0000000..63c8593
--- /dev/null
+++ b/gd/l2cap/classic/cert/cert.cc
@@ -0,0 +1,531 @@
+/*
+ * 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/classic/cert/cert.h"
+
+#include <condition_variable>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+
+#include "common/blocking_queue.h"
+#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"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+using ::bluetooth::l2cap::classic::cert::L2capPacket;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace cert {
+
+using namespace facade;
+
+constexpr auto kEventTimeout = std::chrono::seconds(1);
+
+class L2capModuleCertService : public L2capModuleCert::Service {
+ public:
+  L2capModuleCertService(hci::AclManager* acl_manager, os::Handler* facade_handler)
+      : handler_(facade_handler), acl_manager_(acl_manager) {
+    ASSERT(handler_ != nullptr);
+    acl_manager_->RegisterCallbacks(&acl_callbacks, handler_);
+  }
+
+  ::grpc::Status SetupLink(::grpc::ServerContext* context,
+                           const ::bluetooth::l2cap::classic::cert::SetupLinkRequest* request,
+                           ::bluetooth::l2cap::classic::cert::SetupLinkResponse* response) override {
+    hci::Address address;
+    hci::Address::FromString(request->remote().address(), address);
+    LOG_INFO("%s", address.ToString().c_str());
+    acl_manager_->CreateConnection(address);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const L2capPacket* request,
+                                 ::google::protobuf::Empty* response) override {
+    std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
+    auto req_string = request->payload();
+    packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+    std::unique_ptr<BasicFrameBuilder> l2cap_builder = BasicFrameBuilder::Create(request->channel(), std::move(packet));
+    outgoing_packet_queue_.push(std::move(l2cap_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());
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendConnectionResponse(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConnectionResponse* request,
+      ::bluetooth::l2cap::classic::cert::SendConnectionResponseResult* response) override {
+    auto builder = ConnectionResponseBuilder::Create(request->signal_id(), request->dcid(), request->scid(),
+                                                     ConnectionResponseResult::SUCCESS,
+                                                     ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendConfigurationRequest(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationRequest* request,
+      ::bluetooth::l2cap::classic::cert::SendConfigurationRequestResult* response) override {
+    std::vector<std::unique_ptr<ConfigurationOption>> config;
+    if (request->retransmission_config().mode() == ChannelRetransmissionFlowControlMode::ERTM) {
+      auto option = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+      option->mode_ = RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+      option->tx_window_size_ = 10;
+      option->max_transmit_ = 20;
+      option->retransmission_time_out_ = 2000;
+      option->monitor_time_out_ = 12000;
+      option->maximum_pdu_size_ = 1010;
+      config.push_back(std::move(option));
+      auto no_fcs = std::make_unique<FrameCheckSequenceOption>();
+      no_fcs->fcs_type_ = FcsType::NO_FCS;
+      config.push_back(std::move(no_fcs));
+    }
+    auto builder = ConfigurationRequestBuilder::Create(request->signal_id(), request->dcid(), Continuation::END,
+                                                       std::move(config));
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendConfigurationResponse(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationResponse* request,
+      ::bluetooth::l2cap::classic::cert::SendConfigurationResponseResult* response) override {
+    std::vector<std::unique_ptr<ConfigurationOption>> config;
+    if (request->retransmission_config().mode() == ChannelRetransmissionFlowControlMode::ERTM) {
+      auto option = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+      option->mode_ = RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+      option->tx_window_size_ = 10;
+      option->max_transmit_ = 20;
+      option->retransmission_time_out_ = 2000;
+      option->monitor_time_out_ = 12000;
+      option->maximum_pdu_size_ = 1010;
+      config.push_back(std::move(option));
+    }
+    auto builder = ConfigurationResponseBuilder::Create(request->signal_id(), request->scid(), Continuation::END,
+                                                        ConfigurationResponseResult::SUCCESS, std::move(config));
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendDisconnectionRequest(::grpc::ServerContext* context, const cert::DisconnectionRequest* request,
+                                          ::google::protobuf::Empty* response) override {
+    auto builder = DisconnectionRequestBuilder::Create(request->signal_id(), request->dcid(), request->scid());
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendDisconnectionResponse(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::DisconnectionResponse* request,
+      ::bluetooth::l2cap::classic::cert::SendDisconnectionResponseResult* response) override {
+    auto builder = DisconnectionResponseBuilder::Create(request->signal_id(), request->dcid(), request->scid());
+    auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+    outgoing_packet_queue_.push(std::move(l2cap_builder));
+    send_packet_from_queue();
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendInformationRequest(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::InformationRequest* request,
+      ::bluetooth::l2cap::classic::cert::SendInformationRequestResult* response) override {
+    switch (request->type()) {
+      case InformationRequestType::CONNECTIONLESS_MTU: {
+        auto builder =
+            InformationRequestBuilder::Create(request->signal_id(), InformationRequestInfoType::CONNECTIONLESS_MTU);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      case InformationRequestType::EXTENDED_FEATURES: {
+        auto builder = InformationRequestBuilder::Create(request->signal_id(),
+                                                         InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      case InformationRequestType::FIXED_CHANNELS: {
+        auto builder = InformationRequestBuilder::Create(request->signal_id(),
+                                                         InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      default:
+        break;
+    }
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendInformationResponse(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::InformationResponse* request,
+      ::bluetooth::l2cap::classic::cert::SendInformationResponseResult* response) override {
+    switch (request->type()) {
+      case InformationRequestType::CONNECTIONLESS_MTU: {
+        auto builder = InformationResponseConnectionlessMtuBuilder::Create(request->signal_id(),
+                                                                           InformationRequestResult::SUCCESS, 100);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      case InformationRequestType::EXTENDED_FEATURES: {
+        auto builder = InformationResponseExtendedFeaturesBuilder::Create(
+            request->signal_id(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      case InformationRequestType::FIXED_CHANNELS: {
+        constexpr uint64_t kSignallingChannelMask = 0x02;
+        auto builder = InformationResponseFixedChannelsBuilder::Create(
+            request->signal_id(), InformationRequestResult::SUCCESS, kSignallingChannelMask);
+        auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+        outgoing_packet_queue_.push(std::move(l2cap_builder));
+        send_packet_from_queue();
+        break;
+      }
+      default:
+        break;
+    }
+
+    return ::grpc::Status::OK;
+  }
+
+  std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() {
+    auto basic_frame_builder = std::move(outgoing_packet_queue_.front());
+    outgoing_packet_queue_.pop();
+    if (outgoing_packet_queue_.size() == 0) {
+      acl_connection_->GetAclQueueEnd()->UnregisterEnqueue();
+    }
+    return basic_frame_builder;
+  }
+
+  ::grpc::Status FetchL2capLog(::grpc::ServerContext* context, const FetchL2capLogRequest* request,
+                               ::grpc::ServerWriter<FetchL2capLogResponse>* writer) override {
+    fetching_l2cap_log_ = true;
+    while (!context->IsCancelled() && fetching_l2cap_log_) {
+      if (!l2cap_log_.empty()) {
+        auto& response = l2cap_log_.front();
+        writer->Write(response);
+        l2cap_log_.pop();
+      } else {
+        std::unique_lock<std::mutex> lock(l2cap_log_mutex_);
+        // TODO(hsz): Rather than hardcode 1 second wait time, we can add another RPC to allow client to inform the
+        // server to return the RPC early
+        auto status = l2cap_log_cv_.wait_for(lock, kEventTimeout);
+        if (status == std::cv_status::timeout) {
+          break;
+        }
+      }
+    }
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status StopFetchingL2capLog(
+      ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::StopFetchingL2capLogRequest* request,
+      ::bluetooth::l2cap::classic::cert::StopFetchingL2capLogResponse* response) override {
+    fetching_l2cap_log_ = false;
+    l2cap_log_cv_.notify_one();
+    return ::grpc::Status::OK;
+  }
+
+  bool fetching_l2cap_log_ = false;
+  std::mutex l2cap_log_mutex_;
+  std::queue<FetchL2capLogResponse> l2cap_log_;
+  std::condition_variable l2cap_log_cv_;
+
+  class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
+   public:
+    void OnWriteResponse(L2capPacket* response, const L2capPacket& event) override {
+      response->CopyFrom(event);
+    }
+
+  } l2cap_stream_callback_;
+  ::bluetooth::grpc::GrpcEventStream<L2capPacket, L2capPacket> l2cap_stream_{&l2cap_stream_callback_};
+
+  void LogEvent(const FetchL2capLogResponse& response) {
+    l2cap_log_.push(response);
+    if (l2cap_log_.size() == 1) {
+      l2cap_log_cv_.notify_one();
+    }
+  }
+
+  void on_incoming_packet() {
+    auto packet = acl_connection_->GetAclQueueEnd()->TryDequeue();
+    BasicFrameView basic_frame_view = BasicFrameView::Create(*packet);
+    ASSERT(basic_frame_view.IsValid());
+    L2capPacket l2cap_packet;
+    auto payload = basic_frame_view.GetPayload();
+    std::string data = std::string(payload.begin(), payload.end());
+    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);
+    } else {
+      FetchL2capLogResponse response;
+      response.mutable_data_packet()->set_channel(basic_frame_view.GetChannelId());
+      response.mutable_data_packet()->set_payload(data);
+      LogEvent(response);
+    }
+  }
+
+  void send_packet_from_queue() {
+    if (outgoing_packet_queue_.size() == 1) {
+      acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
+    }
+  }
+
+  void handle_signalling_packet(ControlView control_view) {
+    auto code = control_view.GetCode();
+    switch (code) {
+      case CommandCode::COMMAND_REJECT: {
+        CommandRejectView view = CommandRejectView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_command_reject()->set_signal_id(control_view.GetIdentifier());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::CONNECTION_REQUEST: {
+        ConnectionRequestView view = ConnectionRequestView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_connection_request()->set_signal_id(control_view.GetIdentifier());
+        response.mutable_connection_request()->set_scid(view.GetSourceCid());
+        response.mutable_connection_request()->set_psm(view.GetPsm());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::CONNECTION_RESPONSE: {
+        ConnectionResponseView view = ConnectionResponseView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_connection_response()->set_signal_id(control_view.GetIdentifier());
+        response.mutable_connection_response()->set_scid(view.GetSourceCid());
+        response.mutable_connection_response()->set_dcid(view.GetDestinationCid());
+        LogEvent(response);
+        break;
+      }
+
+      case CommandCode::CONFIGURATION_REQUEST: {
+        ConfigurationRequestView view = ConfigurationRequestView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_configuration_request()->set_signal_id(control_view.GetIdentifier());
+        response.mutable_configuration_request()->set_dcid(view.GetDestinationCid());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::CONFIGURATION_RESPONSE: {
+        ConfigurationResponseView view = ConfigurationResponseView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_configuration_response()->set_signal_id(control_view.GetIdentifier());
+        response.mutable_configuration_response()->set_scid(view.GetSourceCid());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::DISCONNECTION_RESPONSE: {
+        DisconnectionResponseView view = DisconnectionResponseView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_disconnection_response()->set_signal_id(control_view.GetIdentifier());
+        response.mutable_disconnection_response()->set_dcid(view.GetDestinationCid());
+        response.mutable_disconnection_response()->set_scid(view.GetSourceCid());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::ECHO_RESPONSE: {
+        EchoResponseView view = EchoResponseView::Create(control_view);
+        ASSERT(view.IsValid());
+        FetchL2capLogResponse response;
+        response.mutable_echo_response()->set_signal_id(control_view.GetIdentifier());
+        LogEvent(response);
+        break;
+      }
+      case CommandCode::INFORMATION_REQUEST: {
+        InformationRequestView information_request_view = InformationRequestView::Create(control_view);
+        if (!information_request_view.IsValid()) {
+          return;
+        }
+        FetchL2capLogResponse log_response;
+        log_response.mutable_information_request()->set_signal_id(control_view.GetIdentifier());
+        auto type = information_request_view.GetInfoType();
+        switch (type) {
+          case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+            log_response.mutable_information_request()->set_type(InformationRequestType::CONNECTIONLESS_MTU);
+            break;
+          }
+          case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+            log_response.mutable_information_request()->set_type(InformationRequestType::EXTENDED_FEATURES);
+            break;
+          }
+          case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+            log_response.mutable_information_request()->set_type(InformationRequestType::FIXED_CHANNELS);
+            break;
+          }
+        }
+        LogEvent(log_response);
+        break;
+      }
+      case CommandCode::INFORMATION_RESPONSE: {
+        InformationResponseView information_response_view = InformationResponseView::Create(control_view);
+        if (!information_response_view.IsValid()) {
+          return;
+        }
+        FetchL2capLogResponse log_response;
+        log_response.mutable_information_response()->set_signal_id(control_view.GetIdentifier());
+        auto type = information_response_view.GetInfoType();
+        switch (type) {
+          case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+            auto view = InformationResponseConnectionlessMtuView::Create(information_response_view);
+            if (!view.IsValid()) {
+              return;
+            }
+            log_response.mutable_information_response()->set_type(InformationRequestType::CONNECTIONLESS_MTU);
+            log_response.mutable_information_response()->set_information_value(view.GetConnectionlessMtu());
+            break;
+          }
+          case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+            auto view = InformationResponseExtendedFeaturesView::Create(information_response_view);
+            if (!view.IsValid()) {
+              return;
+            }
+            log_response.mutable_information_response()->set_type(InformationRequestType::EXTENDED_FEATURES);
+            int mask = view.GetEnhancedRetransmissionMode() << 3 | view.GetFcsOption() << 5;
+            log_response.mutable_information_response()->set_information_value(mask);
+            break;
+          }
+          case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+            auto view = InformationResponseFixedChannelsView::Create(information_response_view);
+            if (!view.IsValid()) {
+              return;
+            }
+            log_response.mutable_information_response()->set_type(InformationRequestType::FIXED_CHANNELS);
+            log_response.mutable_information_response()->set_information_value(view.GetFixedChannels());
+            break;
+          }
+        }
+        LogEvent(log_response);
+        break;
+      }
+      default:
+        return;
+    }
+  }
+
+  std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_;
+  ::bluetooth::os::Handler* handler_;
+  hci::AclManager* acl_manager_;
+  std::unique_ptr<hci::AclConnection> acl_connection_;
+
+  class AclCallbacks : public hci::ConnectionCallbacks {
+   public:
+    AclCallbacks(L2capModuleCertService* module) : module_(module) {}
+    void OnConnectSuccess(std::unique_ptr<hci::AclConnection> connection) override {
+      module_->acl_connection_ = std::move(connection);
+      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;
+      FetchL2capLogResponse response;
+      response.mutable_link_up()->mutable_remote()->set_address(module_->acl_connection_->GetAddress().ToString());
+      module_->LogEvent(response);
+    }
+    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};
+
+  std::mutex mutex_;
+};
+
+void L2capModuleCertModule::ListDependencies(ModuleList* list) {
+  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+  list->add<hci::AclManager>();
+  list->add<hci::HciLayer>();
+}
+
+void L2capModuleCertModule::Start() {
+  ::bluetooth::grpc::GrpcFacadeModule::Start();
+  GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
+                                                 common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
+  service_ = new L2capModuleCertService(GetDependency<hci::AclManager>(), GetHandler());
+}
+
+void L2capModuleCertModule::Stop() {
+  delete service_;
+  ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* L2capModuleCertModule::GetService() const {
+  return service_;
+}
+
+const ModuleFactory L2capModuleCertModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new L2capModuleCertModule(); });
+
+}  // namespace cert
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/cert/cert.h b/gd/l2cap/classic/cert/cert.h
similarity index 92%
rename from gd/l2cap/cert/cert.h
rename to gd/l2cap/classic/cert/cert.h
index 07b78d5..c8015d6 100644
--- a/gd/l2cap/cert/cert.h
+++ b/gd/l2cap/classic/cert/cert.h
@@ -3,10 +3,10 @@
 #include <grpc++/grpc++.h>
 
 #include "grpc/grpc_module.h"
-#include "l2cap/l2cap_layer.h"
 
 namespace bluetooth {
 namespace l2cap {
+namespace classic {
 namespace cert {
 
 class L2capModuleCertService;
@@ -26,5 +26,6 @@
 };
 
 }  // namespace cert
+}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/cert/simple_l2cap_test.py b/gd/l2cap/classic/cert/simple_l2cap_test.py
new file mode 100644
index 0000000..38d39b6
--- /dev/null
+++ b/gd/l2cap/classic/cert/simple_l2cap_test.py
@@ -0,0 +1,403 @@
+#!/usr/bin/env python3
+#
+#   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.
+from __future__ import print_function
+
+import os
+import sys
+sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
+
+from cert.gd_base_test import GdBaseTestClass
+from cert import rootservice_pb2 as cert_rootservice_pb2
+from facade import common_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from google.protobuf import empty_pb2
+from l2cap.classic import facade_pb2 as l2cap_facade_pb2
+from l2cap.classic.cert import api_pb2 as l2cap_cert_pb2
+
+import time
+
+ASYNC_OP_TIME_SECONDS = 1  # TODO: Use events to synchronize events instead
+
+class EventHandler:
+    def __init__(self):
+        self._handler_map = {}
+
+    def on(self, matcher, func):
+        self._handler_map[matcher] = func
+
+    def execute(self, grpc_stream):
+        for result in grpc_stream:
+            for matcher, func in self._handler_map.items():
+                if matcher(result):
+                    func(result)
+
+def is_connection_request(log):
+    return log.HasField("connection_request")
+
+def is_connection_response(log):
+    return log.HasField("connection_response")
+
+def is_configuration_request(log):
+    return log.HasField("configuration_request")
+
+def is_configuration_response(log):
+    return log.HasField("configuration_response")
+
+def is_disconnection_request(log):
+    return log.HasField("disconnection_request")
+
+def is_disconnection_response(log):
+    return log.HasField("disconnection_response")
+
+def is_echo_response(log):
+    return log.HasField("echo_response")
+
+def is_information_request(log):
+    return log.HasField("information_request")
+
+def is_information_response(log):
+    return log.HasField("information_response")
+
+def is_command_reject(log):
+    return log.HasField("command_reject")
+
+def basic_frame_to_enhanced_information_frame(information_payload):
+    return information_payload[2:]
+
+class SimpleL2capTest(GdBaseTestClass):
+    def setup_test(self):
+        self.device_under_test = self.gd_devices[0]
+        self.cert_device = self.gd_cert_devices[0]
+        self.device_under_test.rootservice.StartStack(
+            facade_rootservice_pb2.StartStackRequest(
+                module_under_test=facade_rootservice_pb2.BluetoothModule.Value('L2CAP'),
+            )
+        )
+        self.cert_device.rootservice.StartStack(
+            cert_rootservice_pb2.StartStackRequest(
+                module_to_test=cert_rootservice_pb2.BluetoothModule.Value('L2CAP'),
+            )
+        )
+
+        self.device_under_test.wait_channel_ready()
+        self.cert_device.wait_channel_ready()
+
+        dut_address = self.device_under_test.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+        self.device_under_test.address = dut_address
+        cert_address = self.cert_device.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+        self.cert_device.address = cert_address
+
+        self.dut_address = common_pb2.BluetoothAddress(
+            address=self.device_under_test.address)
+        self.cert_address = common_pb2.BluetoothAddress(
+            address=self.cert_device.address)
+
+        log_event_handler = EventHandler()
+        self.next_scid = 0x40
+        self.scid_dcid_map = {}
+        self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.BASIC
+        def handle_connection_request(log):
+            log = log.connection_request
+            self.cert_device.l2cap.SendConnectionResponse(l2cap_cert_pb2.ConnectionResponse(dcid=self.next_scid,scid=log.scid,
+                                                                                            signal_id=log.signal_id))
+            self.scid_dcid_map[self.next_scid] = log.scid
+            self.next_scid += 1
+            self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(
+                dcid=log.scid,
+                signal_id=log.signal_id+1,
+                retransmission_config=l2cap_cert_pb2.ChannelRetransmissionFlowControlConfig(
+                    mode=self.retransmission_mode
+                )))
+        log_event_handler.on(is_connection_request, handle_connection_request)
+
+        def handle_connection_response(log):
+            log = log.connection_response
+            self.scid_dcid_map[log.scid] = log.dcid
+            self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(
+                dcid=log.dcid,
+                signal_id=log.signal_id+1,
+                retransmission_config=l2cap_cert_pb2.ChannelRetransmissionFlowControlConfig(
+                    mode=self.retransmission_mode
+                )))
+        log_event_handler.on(is_connection_response, handle_connection_response)
+
+        def handle_configuration_request(log):
+            log = log.configuration_request
+            if log.dcid not in self.scid_dcid_map:
+                return
+            dcid = self.scid_dcid_map[log.dcid]
+            self.cert_device.l2cap.SendConfigurationResponse(l2cap_cert_pb2.ConfigurationResponse(
+                scid=dcid,
+                signal_id=log.signal_id,
+                ))
+        log_event_handler.on(is_configuration_request, handle_configuration_request)
+
+        def handle_disconnection_request(log):
+            log = log.disconnection_request
+            self.cert_device.l2cap.SendDisconnectionResponse(l2cap_cert_pb2.DisconnectionResponse(dcid=log.dcid,scid=log.scid,
+                                                                                            signal_id=log.signal_id))
+        log_event_handler.on(is_disconnection_request, handle_disconnection_request)
+
+        def handle_information_request(log):
+            log = log.information_request
+            self.cert_device.l2cap.SendInformationResponse(l2cap_cert_pb2.InformationResponse(type=log.type,
+                                                                                      signal_id=log.signal_id))
+        log_event_handler.on(is_information_request, handle_information_request)
+
+        self.event_dump = []
+        def dump_log(log):
+            self.event_dump.append(log)
+        log_event_handler.on(lambda _: True, dump_log)
+        self.event_handler = log_event_handler
+
+    def teardown_test(self):
+        self.device_under_test.rootservice.StopStack(
+            facade_rootservice_pb2.StopStackRequest()
+        )
+        self.cert_device.rootservice.StopStack(
+            cert_rootservice_pb2.StopStackRequest()
+        )
+
+    def _setup_link(self):
+        self.cert_device.l2cap.SetupLink(l2cap_cert_pb2.SetupLinkRequest(remote=self.dut_address))
+        link_up_handled = []
+        def handle_link_up(log):
+            log = log.link_up
+            link_up_handled.append(log.remote)
+        self.event_handler.on(lambda log : log.HasField("link_up"), handle_link_up)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert self.dut_address in link_up_handled
+
+    def _open_channel(self, scid=0x0101, psm=0x33):
+        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=psm))
+
+        configuration_response_handled = []
+        def handle_configuration_response(log):
+            log = log.configuration_response
+            configuration_response_handled.append(log.scid)
+        self.event_handler.on(is_configuration_response, handle_configuration_response)
+        self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=scid, psm=psm))
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert scid in configuration_response_handled
+
+    def test_connect(self):
+        self._setup_link()
+        self._open_channel(scid=0x0101)
+        self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+    def test_connect_and_send_data_ertm_no_segmentation(self):
+        self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.ERTM
+        self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
+        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33, retransmission_mode=l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM))
+        self._setup_link()
+        scid = 0x0101
+        self._open_channel(scid=scid)
+        self.device_under_test.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"123"))
+
+        data_received = []
+        event_handler = EventHandler()
+        def on_data_received(log):
+            log = log.data_packet
+            if (log.channel == scid):
+                log.payload = basic_frame_to_enhanced_information_frame(log.payload)
+            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())
+        event_handler.execute(logs)
+        assert (2, b"123") in data_received
+
+        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'*34))
+        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))
+        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33))
+        self._setup_link()
+        scid = 0x0101
+        self._open_channel(scid=scid)
+        self.device_under_test.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"123"))
+
+        data_received = []
+        event_handler = EventHandler()
+        def on_data_received(log):
+            log = log.data_packet
+            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())
+        event_handler.execute(logs)
+        assert (2, b"123") in data_received
+
+        self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        event_handler.execute(logs)
+        assert (scid, b"abc") in data_received
+        self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+    def test_open_two_channels(self):
+        self._setup_link()
+        self._open_channel(scid=0x0101, psm=0x1)
+        self._open_channel(scid=0x0102, psm=0x3)
+        self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+    def test_accept_disconnect(self):
+        """
+        L2CAP/COS/CED/BV-07-C
+        """
+        self._setup_link()
+        scid=0x0101
+        self._open_channel(scid=scid, psm=0x1)
+        dcid = self.scid_dcid_map[scid]
+        disconnection_response_handled = []
+        def handle_disconnection_response(log):
+            log = log.disconnection_response
+            disconnection_response_handled.append((log.scid, log.dcid))
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_disconnection_response, handle_disconnection_response)
+        self.cert_device.l2cap.SendDisconnectionRequest(l2cap_cert_pb2.DisconnectionRequest(scid=scid, dcid=dcid, signal_id=2))
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert (scid, dcid) in disconnection_response_handled
+
+    def test_disconnect_on_timeout(self):
+        """
+        L2CAP/COS/CED/BV-08-C
+        """
+        self._setup_link()
+        scid = 0x0101
+        psm = 1
+        self._open_channel(scid=0x0101, psm=0x1)
+
+        self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=psm))
+
+        # Don't send configuration response back
+        self.event_handler.on(is_configuration_request, lambda _: True)
+        self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=scid, psm=psm))
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        time.sleep(3)
+        def handle_configuration_response(log):
+            # DUT should not send configuration response due to timeout
+            assert False
+        self.event_handler.on(is_configuration_response, handle_configuration_response)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+
+    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.
+        """
+        psm = 1
+        # TODO: Use another test case
+        self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=psm))
+        connection_request = []
+        def handle_connection_request(log):
+            log = log.connection_request
+            connection_request.append(log.psm)
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_connection_request, handle_connection_request)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert psm in connection_request
+
+    def test_respond_to_echo_request(self):
+        """
+        L2CAP/COS/ECH/BV-01-C [Respond to Echo Request]
+        Verify that the IUT responds to an echo request.
+        """
+        self._setup_link()
+        # TODO: Replace with constructed packets when PDL is available
+        echo_request_packet = b"\x08\x01\x00\x00"
+        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=echo_request_packet))
+        echo_response = []
+        def handle_echo_response(log):
+            log = log.echo_response
+            echo_response.append(log.signal_id)
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_echo_response, handle_echo_response)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert 0x01 in echo_response
+
+    def test_reject_unknown_command(self):
+        """
+        L2CAP/COS/CED/BI-01-C
+        """
+        self._setup_link()
+        # TODO: Replace with constructed packets when PDL is available
+        invalid_command_packet = b"\xff\x01\x00\x00"
+        self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=invalid_command_packet))
+        command_reject_packet = b"\x01\x01\x02\x00\x00\x00"
+        command_reject = []
+        def handle_command_reject(log):
+            log = log.command_reject
+            command_reject.append(log.signal_id)
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_command_reject, handle_command_reject)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert 0x01 in command_reject
+
+    def test_query_for_1_2_features(self):
+        """
+        L2CAP/COS/IEX/BV-01-C [Query for 1.2 Features]
+        """
+        self._setup_link()
+        signal_id = 3
+        self.cert_device.l2cap.SendInformationRequest(
+            l2cap_cert_pb2.InformationRequest(
+                type=l2cap_cert_pb2.InformationRequestType.FIXED_CHANNELS, signal_id=signal_id))
+        info_response = []
+        def handle_info_response(log):
+            log = log.information_response
+            info_response.append((log.signal_id, log.type))
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_information_response, handle_info_response)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        assert (signal_id, l2cap_cert_pb2.InformationRequestType.FIXED_CHANNELS) in info_response
+
+
+    def test_extended_feature_info_response_ertm(self):
+        """
+        L2CAP/EXF/BV-01-C [Extended Features Information Response for Enhanced
+        Retransmission Mode]
+        """
+        self._setup_link()
+        signal_id = 3
+        self.cert_device.l2cap.SendInformationRequest(
+            l2cap_cert_pb2.InformationRequest(
+                type=l2cap_cert_pb2.InformationRequestType.EXTENDED_FEATURES, signal_id=signal_id))
+        info_response = []
+        def handle_info_response(log):
+            log = log.information_response
+            info_response.append((log.signal_id, log.type, log.information_value))
+            self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+        self.event_handler.on(is_information_response, handle_info_response)
+        logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+        self.event_handler.execute(logs)
+        expected_log_type = l2cap_cert_pb2.InformationRequestType.EXTENDED_FEATURES
+        expected_mask = 1 << 3
+        assert len(info_response) == 1
+        assert info_response[0][0] == signal_id
+        assert info_response[0][1] == expected_log_type
+        assert info_response[0][2] | expected_mask == expected_mask
diff --git a/gd/l2cap/classic/dynamic_channel.cc b/gd/l2cap/classic/dynamic_channel.cc
new file mode 100644
index 0000000..b888b91
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel.cc
@@ -0,0 +1,45 @@
+/*
+ * 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/classic/dynamic_channel.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+hci::Address DynamicChannel::GetDevice() const {
+  return impl_->GetDevice();
+}
+
+void DynamicChannel::RegisterOnCloseCallback(os::Handler* user_handler,
+                                             DynamicChannel::OnCloseCallback on_close_callback) {
+  l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+                                        std::move(on_close_callback)));
+}
+
+void DynamicChannel::Close() {
+  l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::Close, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+DynamicChannel::GetQueueUpEnd() const {
+  return impl_->GetQueueUpEnd();
+}
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/dynamic_channel.h b/gd/l2cap/classic/dynamic_channel.h
new file mode 100644
index 0000000..eb52c16
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel.h
@@ -0,0 +1,81 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class DynamicChannelImpl;
+}  // namespace internal
+
+/**
+ * L2CAP Dynamic channel object. User needs to call Close() when user no longer wants to use it. Otherwise the link
+ * won't be disconnected.
+ */
+class DynamicChannel {
+ public:
+  // Should only be constructed by modules that have access to LinkManager
+  DynamicChannel(std::shared_ptr<internal::DynamicChannelImpl> impl, os::Handler* l2cap_handler)
+      : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+    ASSERT(impl_ != nullptr);
+    ASSERT(l2cap_handler_ != nullptr);
+  }
+
+  hci::Address GetDevice() const;
+
+  /**
+   * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+   * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+   * resource will be freed immediately after closing.
+   *
+   * @param user_handler The handler used to invoke the callback on
+   * @param on_close_callback The callback invoked upon channel closing.
+   */
+  using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+  void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+  /**
+   * Indicate that this Dynamic Channel should be closed. OnCloseCallback will be invoked when channel close is done.
+   * L2cay layer may terminate this ACL connection to free the resource after channel is closed.
+   */
+  void Close();
+
+  /**
+   * This method will retrieve the data channel queue to send and receive packets.
+   *
+   * {@see BidiQueueEnd}
+   *
+   * @return The upper end of a bi-directional queue.
+   */
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+  std::shared_ptr<internal::DynamicChannelImpl> impl_;
+  os::Handler* l2cap_handler_;
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_configuration_option.h b/gd/l2cap/classic/dynamic_channel_configuration_option.h
new file mode 100644
index 0000000..3f3cc02
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_configuration_option.h
@@ -0,0 +1,48 @@
+/*
+ * 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 "l2cap/mtu.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+/**
+ * Configuration Option specified by L2CAP Channel user on a dynamic channel. L2CAP module will configure the channel
+ * based on user provided option.
+ */
+struct DynamicChannelConfigurationOption {
+  enum class RetransmissionAndFlowControlMode {
+    L2CAP_BASIC,
+    ENHANCED_RETRANSMISSION,
+  };
+  /**
+   * Retransmission and flow control mode. Currently L2CAP_BASIC and ENHANCED_RETRANSMISSION.
+   * If the remote doesn't support a mode, it might fall back to basic, as this is a negotiable option.
+   */
+  RetransmissionAndFlowControlMode channel_mode = RetransmissionAndFlowControlMode::L2CAP_BASIC;
+
+  /**
+   * Maximum SDU size that the L2CAP Channel user is able to process.
+   */
+  Mtu incoming_mtu = kDefaultClassicMtu;
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_manager.cc b/gd/l2cap/classic/dynamic_channel_manager.cc
new file mode 100644
index 0000000..123fdd4
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_manager.cc
@@ -0,0 +1,62 @@
+/*
+ * 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/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+bool DynamicChannelManager::ConnectChannel(hci::Address device, DynamicChannelConfigurationOption configuration_option,
+                                           Psm psm, OnConnectionOpenCallback on_connection_open,
+                                           OnConnectionFailureCallback on_fail_callback, os::Handler* handler) {
+  internal::Link::PendingDynamicChannelConnection pending_dynamic_channel_connection{
+      .handler_ = handler,
+      .on_open_callback_ = std::move(on_connection_open),
+      .on_fail_callback_ = std::move(on_fail_callback),
+      .configuration_ = configuration_option,
+  };
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectDynamicChannelServices,
+                                              common::Unretained(link_manager_), device,
+                                              std::move(pending_dynamic_channel_connection), psm));
+
+  return true;
+}
+
+bool DynamicChannelManager::RegisterService(Psm psm, DynamicChannelConfigurationOption configuration_option,
+                                            const SecurityPolicy& security_policy,
+                                            OnRegistrationCompleteCallback on_registration_complete,
+                                            OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+  internal::DynamicChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = handler,
+      .on_registration_complete_callback_ = std::move(on_registration_complete),
+      .on_connection_open_callback_ = std::move(on_connection_open),
+      .configuration_ = configuration_option,
+  };
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::DynamicChannelServiceManagerImpl::Register,
+                                              common::Unretained(service_manager_), psm,
+                                              std::move(pending_registration)));
+
+  return true;
+}
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_manager.h b/gd/l2cap/classic/dynamic_channel_manager.h
new file mode 100644
index 0000000..340d68d
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_manager.h
@@ -0,0 +1,145 @@
+/*
+ * 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 "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule;
+
+namespace internal {
+class LinkManager;
+class DynamicChannelServiceManagerImpl;
+}  // namespace internal
+
+class DynamicChannelManager {
+ public:
+  enum class ConnectionResultCode {
+    SUCCESS = 0,
+    FAIL_NO_SERVICE_REGISTERED = 1,  // No service is registered
+    FAIL_HCI_ERROR = 2,              // See hci_error
+    FAIL_L2CAP_ERROR = 3,            // See l2cap_connection_response_result
+  };
+
+  struct ConnectionResult {
+    ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+    hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+    ConnectionResponseResult l2cap_connection_response_result = ConnectionResponseResult::SUCCESS;
+  };
+  /**
+   * OnConnectionFailureCallback(std::string failure_reason);
+   */
+  using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+
+  /**
+   * OnConnectionOpenCallback(DynamicChannel channel);
+   */
+  using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<DynamicChannel>)>;
+
+  enum class RegistrationResult {
+    SUCCESS = 0,
+    FAIL_DUPLICATE_SERVICE = 1,  // Duplicate service registration for the same PSM
+    FAIL_INVALID_SERVICE = 2,    // Invalid PSM
+  };
+
+  /**
+   * OnRegistrationFailureCallback(RegistrationResult result, DynamicChannelService service);
+   */
+  using OnRegistrationCompleteCallback =
+      common::OnceCallback<void(RegistrationResult, std::unique_ptr<DynamicChannelService>)>;
+
+  /**
+   * Connect to a Dynamic channel on a remote device
+   *
+   * - This method is asynchronous
+   * - When false is returned, the connection fails immediately
+   * - When true is returned, method caller should wait for on_fail_callback or on_open_callback
+   * - If an ACL connection does not exist, this method will create an ACL connection
+   * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+   * - If Dynamic channel on a remote device is already reported as connected via on_open_callback, it won't be
+   *   reported again
+   *
+   * @param device: Remote device to make this connection.
+   * @param psm: Service PSM to connect. PSM is defined in Core spec Vol 3 Part A 4.2.
+   * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+   * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+   * @param handler: The handler context in which to execute the @callback parameters.
+   * @param configuration_option: The configuration options for this channel
+   *
+   * Returns: true if connection was able to be initiated, false otherwise.
+   */
+  bool ConnectChannel(hci::Address device, DynamicChannelConfigurationOption configuration_option, Psm psm,
+                      OnConnectionOpenCallback on_connection_open, OnConnectionFailureCallback on_fail_callback,
+                      os::Handler* handler);
+
+  /**
+   * Register a service to receive incoming connections bound to a specific channel.
+   *
+   * - This method is asynchronous.
+   * - When false is returned, the registration fails immediately.
+   * - When true is returned, method caller should wait for on_service_registered callback that contains a
+   *   DynamicChannelService object. The registered service can be managed from that object.
+   * - If a PSM is already registered or some other error happens, on_registration_complete will be triggered with a
+   *   non-SUCCESS value
+   * - After a service is registered, a DynamicChannel is delivered through on_open_callback when the remote
+   *   initiates a channel open and channel is opened successfully
+   * - on_open_callback, will only be triggered after on_service_registered callback
+   *
+   * @param security_policy: The security policy used for the connection.
+   * @param psm: Service PSM to register. PSM is defined in Core spec Vol 3 Part A 4.2.
+   * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+   *        not SUCCESS, it means service is not registered due to reasons like PSM already take
+   * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+   * @param handler: The handler context in which to execute the @callback parameter.
+   * @param configuration_option: The configuration options for this channel
+   */
+  bool RegisterService(Psm psm, DynamicChannelConfigurationOption configuration_option,
+                       const SecurityPolicy& security_policy, OnRegistrationCompleteCallback on_registration_complete,
+                       OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+  friend class L2capClassicModule;
+
+ private:
+  // The constructor is not to be used by user code
+  DynamicChannelManager(internal::DynamicChannelServiceManagerImpl* service_manager,
+                        internal::LinkManager* link_manager, os::Handler* l2cap_layer_handler)
+      : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {
+    ASSERT(service_manager_ != nullptr);
+    ASSERT(link_manager_ != nullptr);
+    ASSERT(l2cap_layer_handler_ != nullptr);
+  }
+  internal::DynamicChannelServiceManagerImpl* service_manager_ = nullptr;
+  internal::LinkManager* link_manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  DISALLOW_COPY_AND_ASSIGN(DynamicChannelManager);
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_service.cc b/gd/l2cap/classic/dynamic_channel_service.cc
new file mode 100644
index 0000000..ee97d37
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_service.cc
@@ -0,0 +1,38 @@
+/*
+ * 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/classic/dynamic_channel_service.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+void DynamicChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+  ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::DynamicChannelServiceManagerImpl::Unregister,
+                                              common::Unretained(manager_), psm_, std::move(on_unregistered),
+                                              on_unregistered_handler));
+}
+
+Psm DynamicChannelService::GetPsm() const {
+  return psm_;
+}
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_service.h b/gd/l2cap/classic/dynamic_channel_service.h
new file mode 100644
index 0000000..cd24b61
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_service.h
@@ -0,0 +1,65 @@
+/*
+ * 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 "common/callback.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class DynamicChannelServiceManagerImpl;
+}
+
+class DynamicChannelService {
+ public:
+  DynamicChannelService() = default;
+
+  using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+  /**
+   * Unregister a service from L2CAP module. This operation cannot fail.
+   * All channels opened for this service will be closed.
+   *
+   * @param on_unregistered will be triggered when unregistration is complete
+   */
+  void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+  friend internal::DynamicChannelServiceManagerImpl;
+
+  Psm GetPsm() const;
+
+ private:
+  DynamicChannelService(Psm psm, internal::DynamicChannelServiceManagerImpl* manager, os::Handler* handler)
+      : psm_(psm), manager_(manager), l2cap_layer_handler_(handler) {
+    ASSERT(IsPsmValid(psm));
+    ASSERT(manager_ != nullptr);
+    ASSERT(l2cap_layer_handler_ != nullptr);
+  }
+  Psm psm_ = kDefaultPsm;
+  internal::DynamicChannelServiceManagerImpl* manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_;
+  DISALLOW_COPY_AND_ASSIGN(DynamicChannelService);
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/facade.cc b/gd/l2cap/classic/facade.cc
new file mode 100644
index 0000000..9613c75
--- /dev/null
+++ b/gd/l2cap/classic/facade.cc
@@ -0,0 +1,369 @@
+/*
+ * 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 <cstdint>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "grpc/grpc_event_stream.h"
+#include "hci/address.h"
+#include "hci/facade.h"
+#include "l2cap/classic/facade.grpc.pb.h"
+#include "l2cap/classic/facade.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capModuleFacadeService : public L2capModuleFacade::Service {
+ public:
+  L2capModuleFacadeService(L2capClassicModule* l2cap_layer, os::Handler* facade_handler)
+      : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler) {
+    ASSERT(l2cap_layer_ != nullptr);
+    ASSERT(facade_handler_ != nullptr);
+  }
+
+  class ConnectionCompleteCallback
+      : public grpc::GrpcEventStreamCallback<ConnectionCompleteEvent, ConnectionCompleteEvent> {
+   public:
+    void OnWriteResponse(ConnectionCompleteEvent* response, const ConnectionCompleteEvent& event) override {
+      response->CopyFrom(event);
+    }
+
+  } connection_complete_callback_;
+  ::bluetooth::grpc::GrpcEventStream<ConnectionCompleteEvent, ConnectionCompleteEvent> connection_complete_stream_{
+      &connection_complete_callback_};
+
+  ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context,
+                                         const ::bluetooth::facade::EventStreamRequest* request,
+                                         ::grpc::ServerWriter<classic::ConnectionCompleteEvent>* writer) override {
+    return connection_complete_stream_.HandleRequest(context, request, writer);
+  }
+
+  ::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+                         ::google::protobuf::Empty* response) override {
+    auto fixed_channel_manager = l2cap_layer_->GetFixedChannelManager();
+    hci::Address peer;
+    ASSERT(hci::Address::FromString(request->address(), peer));
+    fixed_channel_manager->ConnectServices(peer, common::BindOnce([](FixedChannelManager::ConnectionResult) {}),
+                                           facade_handler_);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const classic::L2capPacket* request,
+                                 SendL2capPacketResult* response) override {
+    if (fixed_channel_helper_map_.find(request->channel()) == fixed_channel_helper_map_.end()) {
+      return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Channel not registered");
+    }
+    std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
+    fixed_channel_helper_map_[request->channel()]->SendPacket(packet);
+    response->set_result_type(SendL2capPacketResultType::OK);
+    return ::grpc::Status::OK;
+  }
+
+  ::grpc::Status SendDynamicChannelPacket(::grpc::ServerContext* context, const DynamicChannelPacket* request,
+                                          ::google::protobuf::Empty* response) override {
+    if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
+      return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
+    }
+    std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
+    dynamic_channel_helper_map_[request->psm()]->SendPacket(packet);
+    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();
+    auto mode = request->mode();
+    dynamic_channel_helper_map_.emplace(
+        psm, std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, psm, mode));
+    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);
+  }
+
+  ::grpc::Status RegisterChannel(::grpc::ServerContext* context, const classic::RegisterChannelRequest* request,
+                                 ::google::protobuf::Empty* response) override {
+    if (fixed_channel_helper_map_.find(request->channel()) != fixed_channel_helper_map_.end()) {
+      return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Already registered");
+    }
+    fixed_channel_helper_map_.emplace(request->channel(), std::make_unique<L2capFixedChannelHelper>(
+                                                              this, l2cap_layer_, facade_handler_, request->channel()));
+
+    return ::grpc::Status::OK;
+  }
+
+  class L2capFixedChannelHelper {
+   public:
+    L2capFixedChannelHelper(L2capModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler,
+                            Cid cid)
+        : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), cid_(cid) {
+      fixed_channel_manager_ = l2cap_layer_->GetFixedChannelManager();
+      fixed_channel_manager_->RegisterService(
+          cid, {},
+          common::BindOnce(&L2capFixedChannelHelper::on_l2cap_service_registration_complete, common::Unretained(this)),
+          common::Bind(&L2capFixedChannelHelper::on_connection_open, common::Unretained(this)), handler_);
+    }
+
+    void on_l2cap_service_registration_complete(FixedChannelManager::RegistrationResult registration_result,
+                                                std::unique_ptr<FixedChannelService> service) {
+      service_ = std::move(service);
+    }
+
+    void on_connection_open(std::unique_ptr<FixedChannel> channel) {
+      ConnectionCompleteEvent event;
+      event.mutable_remote()->set_address(channel->GetDevice().ToString());
+      facade_service_->connection_complete_stream_.OnIncomingEvent(event);
+      channel_ = std::move(channel);
+    }
+
+    void SendPacket(std::vector<uint8_t> packet) {
+      if (channel_ == nullptr) {
+        LOG_WARN("Channel is not open");
+        return;
+      }
+      channel_->GetQueueUpEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capFixedChannelHelper::enqueue_callback, common::Unretained(this), packet));
+    }
+
+    void on_incoming_packet() {
+      auto packet = channel_->GetQueueUpEnd()->TryDequeue();
+      std::string data = std::string(packet->begin(), packet->end());
+      L2capPacket l2cap_data;
+      l2cap_data.set_channel(cid_);
+      l2cap_data.set_payload(data);
+      facade_service_->l2cap_stream_.OnIncomingEvent(l2cap_data);
+    }
+
+    std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+      auto packet_one = std::make_unique<packet::RawBuilder>();
+      packet_one->AddOctets(packet);
+      channel_->GetQueueUpEnd()->UnregisterEnqueue();
+      return packet_one;
+    };
+
+    L2capModuleFacadeService* facade_service_;
+    L2capClassicModule* l2cap_layer_;
+    os::Handler* handler_;
+    std::unique_ptr<FixedChannelManager> fixed_channel_manager_;
+    std::unique_ptr<FixedChannelService> service_;
+    std::unique_ptr<FixedChannel> channel_ = nullptr;
+    Cid cid_;
+  };
+
+  ::grpc::Status SetDynamicChannel(::grpc::ServerContext* context, const SetEnableDynamicChannelRequest* request,
+                                   google::protobuf::Empty* response) override {
+    dynamic_channel_helper_map_.emplace(
+        request->psm(), std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, request->psm(),
+                                                                    request->retransmission_mode()));
+    return ::grpc::Status::OK;
+  }
+
+  class L2capDynamicChannelHelper {
+   public:
+    L2capDynamicChannelHelper(L2capModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler,
+                              Psm psm, RetransmissionFlowControlMode mode)
+        : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) {
+      dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager();
+      DynamicChannelConfigurationOption configuration_option;
+      if (mode == RetransmissionFlowControlMode::BASIC) {
+        configuration_option.channel_mode =
+            DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+      } else if (mode == RetransmissionFlowControlMode::ERTM) {
+        configuration_option.channel_mode =
+            DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION;
+      }
+      dynamic_channel_manager_->RegisterService(
+          psm, configuration_option, {},
+          common::BindOnce(&L2capDynamicChannelHelper::on_l2cap_service_registration_complete,
+                           common::Unretained(this)),
+          common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_);
+    }
+
+    void Connect(hci::Address address) {
+      // TODO: specify channel mode
+      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) {}
+
+    void on_connection_open(std::unique_ptr<DynamicChannel> channel) {
+      ConnectionCompleteEvent event;
+      event.mutable_remote()->set_address(channel->GetDevice().ToString());
+      facade_service_->connection_complete_stream_.OnIncomingEvent(event);
+      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());
+      L2capPacket l2cap_data;
+      //      l2cap_data.set_channel(cid_);
+      l2cap_data.set_payload(data);
+      facade_service_->l2cap_stream_.OnIncomingEvent(l2cap_data);
+    }
+
+    void SendPacket(std::vector<uint8_t> packet) {
+      if (channel_ == nullptr) {
+        LOG_WARN("Channel is not open");
+        return;
+      }
+      channel_->GetQueueUpEnd()->RegisterEnqueue(
+          handler_, common::Bind(&L2capDynamicChannelHelper::enqueue_callback, common::Unretained(this), packet));
+    }
+
+    std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+      auto packet_one = std::make_unique<packet::RawBuilder>(2000);
+      packet_one->AddOctets(packet);
+      channel_->GetQueueUpEnd()->UnregisterEnqueue();
+      return packet_one;
+    };
+
+    L2capModuleFacadeService* facade_service_;
+    L2capClassicModule* l2cap_layer_;
+    os::Handler* handler_;
+    std::unique_ptr<DynamicChannelManager> dynamic_channel_manager_;
+    std::unique_ptr<DynamicChannelService> service_;
+    std::unique_ptr<DynamicChannel> channel_ = nullptr;
+    Psm psm_;
+  };
+
+  L2capClassicModule* l2cap_layer_;
+  ::bluetooth::os::Handler* facade_handler_;
+  std::map<Cid, std::unique_ptr<L2capFixedChannelHelper>> fixed_channel_helper_map_;
+  std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_;
+
+  class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
+   public:
+    L2capStreamCallback(L2capModuleFacadeService* service) : service_(service) {}
+
+    ~L2capStreamCallback() {
+      for (const auto& connection : service_->fixed_channel_helper_map_) {
+        if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_fixed_channel_[connection.first] = false;
+        }
+      }
+
+      for (const auto& connection : service_->dynamic_channel_helper_map_) {
+        if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_dynamic_channel_[connection.first] = false;
+        }
+      }
+    }
+
+    void OnSubscribe() override {
+      for (auto& connection : service_->fixed_channel_helper_map_) {
+        if (!subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
+              service_->facade_handler_,
+              common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(connection.second.get())));
+          subscribed_fixed_channel_[connection.first] = true;
+        }
+      }
+
+      for (auto& connection : service_->dynamic_channel_helper_map_) {
+        if (!subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
+              service_->facade_handler_, common::Bind(&L2capDynamicChannelHelper::on_incoming_packet,
+                                                      common::Unretained(connection.second.get())));
+          subscribed_dynamic_channel_[connection.first] = true;
+        }
+      }
+    }
+
+    void OnUnsubscribe() override {
+      for (const auto& connection : service_->fixed_channel_helper_map_) {
+        if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_fixed_channel_[connection.first] = false;
+        }
+      }
+
+      for (const auto& connection : service_->dynamic_channel_helper_map_) {
+        if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+          connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+          subscribed_dynamic_channel_[connection.first] = false;
+        }
+      }
+    }
+
+    void OnWriteResponse(L2capPacket* response, const L2capPacket& event) override {
+      response->CopyFrom(event);
+    }
+
+    L2capModuleFacadeService* service_;
+    std::map<Cid, bool> subscribed_fixed_channel_;
+    std::map<Psm, bool> subscribed_dynamic_channel_;
+
+  } l2cap_stream_callback_{this};
+  ::bluetooth::grpc::GrpcEventStream<L2capPacket, L2capPacket> l2cap_stream_{&l2cap_stream_callback_};
+
+  std::mutex mutex_;
+};
+
+void L2capModuleFacadeModule::ListDependencies(ModuleList* list) {
+  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+  list->add<l2cap::classic::L2capClassicModule>();
+  list->add<hci::HciLayer>();
+}
+
+void L2capModuleFacadeModule::Start() {
+  ::bluetooth::grpc::GrpcFacadeModule::Start();
+  GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
+                                                 common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
+  service_ = new L2capModuleFacadeService(GetDependency<l2cap::classic::L2capClassicModule>(), GetHandler());
+}
+
+void L2capModuleFacadeModule::Stop() {
+  delete service_;
+  ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* L2capModuleFacadeModule::GetService() const {
+  return service_;
+}
+
+const ModuleFactory L2capModuleFacadeModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new L2capModuleFacadeModule(); });
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/facade.h b/gd/l2cap/classic/facade.h
similarity index 95%
rename from gd/l2cap/facade.h
rename to gd/l2cap/classic/facade.h
index 734d261..425940a 100644
--- a/gd/l2cap/facade.h
+++ b/gd/l2cap/classic/facade.h
@@ -20,6 +20,7 @@
 
 namespace bluetooth {
 namespace l2cap {
+namespace classic {
 
 class L2capModuleFacadeService;
 
@@ -37,5 +38,6 @@
   L2capModuleFacadeService* service_;
 };
 
+}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/facade.proto b/gd/l2cap/classic/facade.proto
new file mode 100644
index 0000000..7eb780d
--- /dev/null
+++ b/gd/l2cap/classic/facade.proto
@@ -0,0 +1,94 @@
+syntax = "proto3";
+
+package bluetooth.l2cap.classic;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service L2capModuleFacade {
+  rpc RegisterChannel(RegisterChannelRequest) returns (google.protobuf.Empty) {
+    // Testing Android Bluetooth stack only. Optional for other stack.
+  }
+  rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {
+    // Testing Android Bluetooth stack only. Optional for other stack.
+  }
+  rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+  rpc OpenChannel(OpenChannelRequest) returns (google.protobuf.Empty) {}
+  rpc ConfigureChannel(ConfigureChannelRequest) returns (google.protobuf.Empty) {}
+  rpc SendL2capPacket(L2capPacket) returns (SendL2capPacketResult) {}
+  rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {}
+  rpc RegisterDynamicChannel(RegisterDynamicChannelRequest) returns (google.protobuf.Empty) {}
+  rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (google.protobuf.Empty) {}
+  rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (google.protobuf.Empty) {}
+}
+
+message RegisterChannelRequest {
+  uint32 channel = 1;
+}
+
+message ConnectionCompleteEvent {
+  facade.BluetoothAddress remote = 1;
+}
+
+enum RetransmissionFlowControlMode {
+  BASIC = 0;
+  ERTM = 3;
+}
+
+message OpenChannelRequest {
+  facade.BluetoothAddress remote = 1;
+  uint32 psm = 2;
+  RetransmissionFlowControlMode mode = 3;
+}
+
+message ConfigureChannelRequest {
+  facade.BluetoothAddress remote = 1;
+  // Config
+}
+
+message CloseChannelRequest {
+  facade.BluetoothAddress remote = 1;
+  uint32 cid = 2;
+}
+
+enum ChannelSignalEventType {
+  OPEN = 0;
+  CLOSE = 1;
+  CONFIGURE = 2;
+}
+
+message ChannelSignalEvent {
+  uint32 cid = 1;
+  ChannelSignalEventType type = 2;
+}
+
+enum SendL2capPacketResultType {
+  OK = 0;
+  BAD_CID = 1;
+}
+
+message SendL2capPacketResult {
+  SendL2capPacketResultType result_type = 1;
+}
+
+message L2capPacket {
+  facade.BluetoothAddress remote = 1;
+  uint32 channel = 2;
+  bytes payload = 3;
+}
+
+message RegisterDynamicChannelRequest {
+  uint32 psm = 1;
+}
+
+message SetEnableDynamicChannelRequest {
+  uint32 psm = 1;
+  bool enable = 2;
+  RetransmissionFlowControlMode retransmission_mode = 3;
+}
+
+message DynamicChannelPacket {
+  facade.BluetoothAddress remote = 1;
+  uint32 psm = 2;
+  bytes payload = 3;
+}
diff --git a/gd/l2cap/classic/fixed_channel.cc b/gd/l2cap/classic/fixed_channel.cc
new file mode 100644
index 0000000..a90d119
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel.cc
@@ -0,0 +1,48 @@
+/*
+ * 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/classic/fixed_channel.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+hci::Address FixedChannel::GetDevice() const {
+  return impl_->GetDevice();
+}
+
+void FixedChannel::RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback) {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+                                        std::move(on_close_callback)));
+}
+
+void FixedChannel::Acquire() {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Acquire, impl_));
+}
+
+void FixedChannel::Release() {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Release, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+FixedChannel::GetQueueUpEnd() const {
+  return impl_->GetQueueUpEnd();
+}
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/fixed_channel.h b/gd/l2cap/classic/fixed_channel.h
new file mode 100644
index 0000000..bf88e3d
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel.h
@@ -0,0 +1,90 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class FixedChannelImpl;
+}  // namespace internal
+
+/**
+ * L2CAP fixed channel object. When a new object is created, it must be
+ * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
+ * Otherwise, {@link FixedChannel#Release()} will be called automatically.
+ *
+ */
+class FixedChannel {
+ public:
+  // Should only be constructed by modules that have access to LinkManager
+  FixedChannel(std::shared_ptr<internal::FixedChannelImpl> impl, os::Handler* l2cap_handler)
+      : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+    ASSERT(impl_ != nullptr);
+    ASSERT(l2cap_handler_ != nullptr);
+  }
+
+  hci::Address GetDevice() const;
+
+  /**
+   * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+   * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+   * resource will be freed immediately after closing.
+   *
+   * @param user_handler The handler used to invoke the callback on
+   * @param on_close_callback The callback invoked upon channel closing.
+   */
+  using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+  void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+  /**
+   * Indicate that this Fixed Channel is being used. This will prevent ACL connection from being disconnected.
+   */
+  void Acquire();
+
+  /**
+   * Indicate that this Fixed Channel is no longer being used. ACL connection will be disconnected after
+   * kLinkIdleDisconnectTimeout if no other DynamicChannel is connected or no other Fixed Channel is  using this
+   * ACL connection. However a module can still receive data on this channel as long as it remains open.
+   */
+  void Release();
+
+  /**
+   * This method will retrieve the data channel queue to send and receive packets.
+   *
+   * {@see BidiQueueEnd}
+   *
+   * @return The upper end of a bi-directional queue.
+   */
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+  std::shared_ptr<internal::FixedChannelImpl> impl_;
+  os::Handler* l2cap_handler_;
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_manager.cc b/gd/l2cap/classic/fixed_channel_manager.cc
new file mode 100644
index 0000000..0c3e5c7
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager.cc
@@ -0,0 +1,53 @@
+/*
+ * 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/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+bool FixedChannelManager::ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback,
+                                          os::Handler* handler) {
+  internal::LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = handler,
+      .on_fail_callback_ = std::move(on_fail_callback),
+  };
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectFixedChannelServices,
+                                              common::Unretained(link_manager_), device,
+                                              std::move(pending_fixed_channel_connection)));
+  return true;
+}
+
+bool FixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
+                                          OnRegistrationCompleteCallback on_registration_complete,
+                                          OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+  internal::FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = handler,
+      .on_registration_complete_callback_ = std::move(on_registration_complete),
+      .on_connection_open_callback_ = std::move(on_connection_open)};
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Register,
+                                              common::Unretained(service_manager_), cid,
+                                              std::move(pending_registration)));
+  return true;
+}
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_manager.h b/gd/l2cap/classic/fixed_channel_manager.h
new file mode 100644
index 0000000..69812df
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager.h
@@ -0,0 +1,146 @@
+/*
+ * 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 "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule;
+
+namespace internal {
+class LinkManager;
+class FixedChannelServiceManagerImpl;
+}  // namespace internal
+
+class FixedChannelManager {
+ public:
+  enum class ConnectionResultCode {
+    SUCCESS = 0,
+    FAIL_NO_SERVICE_REGISTERED = 1,      // No service is registered
+    FAIL_ALL_SERVICES_HAVE_CHANNEL = 2,  // All registered services already have a channel
+    FAIL_HCI_ERROR = 3,                  // See hci_error
+  };
+
+  struct ConnectionResult {
+    ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+    hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+  };
+  /**
+   * OnConnectionFailureCallback(std::string failure_reason);
+   */
+  using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+
+  /**
+   * OnConnectionOpenCallback(FixedChannel channel);
+   */
+  using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<FixedChannel>)>;
+
+  enum class RegistrationResult {
+    SUCCESS = 0,
+    FAIL_DUPLICATE_SERVICE = 1,  // Duplicate service registration for the same CID
+    FAIL_INVALID_SERVICE = 2,    // Invalid CID
+  };
+
+  /**
+   * OnRegistrationFailureCallback(RegistrationResult result, FixedChannelService service);
+   */
+  using OnRegistrationCompleteCallback =
+      common::OnceCallback<void(RegistrationResult, std::unique_ptr<FixedChannelService>)>;
+
+  /**
+   * Connect to ALL fixed channels on a remote device
+   *
+   * - This method is asynchronous
+   * - When false is returned, the connection fails immediately
+   * - When true is returned, method caller should wait for on_fail_callback or on_open_callback registered through
+   *   RegisterService() API.
+   * - If an ACL connection does not exist, this method will create an ACL connection. As a result, on_open_callback
+   *   supplied through RegisterService() will be triggered to provide the actual FixedChannel objects
+   * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+   * - If fixed channel on a remote device is already reported as connected via on_open_callback and has been acquired
+   *   via FixedChannel#Acquire() API, it won't be reported again
+   * - If no service is registered, on_fail_callback will be triggered with FAIL_NO_SERVICE_REGISTERED
+   * - If there is an ACL connection and channels for each service is allocated, on_fail_callback will be triggered with
+   *   FAIL_ALL_SERVICES_HAVE_CHANNEL
+   *
+   * NOTE:
+   * This call will initiate an effort to connect all fixed channel services on a remote device.
+   * Due to the connectionless nature of fixed channels, all fixed channels will be connected together.
+   * If a fixed channel service does not need a particular fixed channel. It should release the received
+   * channel immediately after receiving on_open_callback via FixedChannel#Release()
+   *
+   * A module calling ConnectServices() must have called RegisterService() before.
+   * The callback will come back from on_open_callback in the service that is registered
+   *
+   * @param device: Remote device to make this connection.
+   * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+   * @param handler: The handler context in which to execute the @callback parameters.
+   *
+   * Returns: true if connection was able to be initiated, false otherwise.
+   */
+  bool ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler);
+
+  /**
+   * Register a service to receive incoming connections bound to a specific channel.
+   *
+   * - This method is asynchronous.
+   * - When false is returned, the registration fails immediately.
+   * - When true is returned, method caller should wait for on_service_registered callback that contains a
+   *   FixedChannelService object. The registered service can be managed from that object.
+   * - If a CID is already registered or some other error happens, on_registration_complete will be triggered with a
+   *   non-SUCCESS value
+   * - After a service is registered, any classic ACL connection will create a FixedChannel object that is
+   *   delivered through on_open_callback
+   * - on_open_callback, will only be triggered after on_service_registered callback
+   *
+   * @param cid:  cid used to receive incoming connections
+   * @param security_policy: The security policy used for the connection.
+   * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+   *        not SUCCESS, it means service is not registered due to reasons like CID already take
+   * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+   * @param handler: The handler context in which to execute the @callback parameter.
+   */
+  bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
+                       OnRegistrationCompleteCallback on_registration_complete,
+                       OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+  friend class L2capClassicModule;
+
+ private:
+  // The constructor is not to be used by user code
+  FixedChannelManager(internal::FixedChannelServiceManagerImpl* service_manager, internal::LinkManager* link_manager,
+                      os::Handler* l2cap_layer_handler)
+      : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {}
+  internal::FixedChannelServiceManagerImpl* service_manager_ = nullptr;
+  internal::LinkManager* link_manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelManager);
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_service.cc b/gd/l2cap/classic/fixed_channel_service.cc
new file mode 100644
index 0000000..49a977d
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_service.cc
@@ -0,0 +1,34 @@
+/*
+ * 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/classic/fixed_channel_service.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+void FixedChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+  ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Unregister,
+                                              common::Unretained(manager_), cid_, std::move(on_unregistered),
+                                              on_unregistered_handler));
+}
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/fixed_channel_service.h b/gd/l2cap/classic/fixed_channel_service.h
new file mode 100644
index 0000000..d5d213b
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_service.h
@@ -0,0 +1,59 @@
+
+/*
+ * 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 "common/callback.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class FixedChannelServiceManagerImpl;
+}  // namespace internal
+
+class FixedChannelService {
+ public:
+  FixedChannelService() = default;
+
+  using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+  /**
+   * Unregister a service from L2CAP module. This operation cannot fail.
+   * All channels opened for this service will be invalidated.
+   *
+   * @param on_unregistered will be triggered when unregistration is complete
+   */
+  void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+  friend internal::FixedChannelServiceManagerImpl;
+
+ private:
+  FixedChannelService(Cid cid, internal::FixedChannelServiceManagerImpl* manager, os::Handler* handler)
+      : cid_(cid), manager_(manager), l2cap_layer_handler_(handler) {}
+  Cid cid_ = kInvalidCid;
+  internal::FixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_;
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelService);
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator.cc
new file mode 100644
index 0000000..95830e0
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator.cc
@@ -0,0 +1,140 @@
+/*
+ * 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(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;
+  }
+  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 nullptr;
+  }
+  auto elem =
+      channels_.try_emplace(cid, std::make_shared<DynamicChannelImpl>(psm, 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);
+  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) {
+    LOG_INFO("Channel is not in use: psm %d, device %s", cid, link_->GetDevice().ToString().c_str());
+    return;
+  }
+  used_remote_cid_.erase(channel->GetRemoteCid());
+  channels_.erase(cid);
+  used_cid_.erase(cid);
+}
+
+bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
+  for (const auto& channel : channels_) {
+    if (channel.second->GetPsm() == psm) {
+      return true;
+    }
+  }
+  return false;
+}
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByCid(Cid cid) {
+  if (channels_.find(cid) == channels_.end()) {
+    LOG_WARN("Can't find cid %d", cid);
+    return nullptr;
+  }
+  return channels_.find(cid)->second;
+}
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByRemoteCid(Cid remote_cid) {
+  for (auto& channel : channels_) {
+    if (channel.second->GetRemoteCid() == remote_cid) {
+      return channel.second;
+    }
+  }
+  return nullptr;
+}
+
+size_t DynamicChannelAllocator::NumberOfChannels() const {
+  return channels_.size();
+}
+
+void DynamicChannelAllocator::OnAclDisconnected(hci::ErrorCode reason) {
+  for (auto& elem : channels_) {
+    elem.second->OnClosed(reason);
+  }
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.h b/gd/l2cap/classic/internal/dynamic_channel_allocator.h
new file mode 100644
index 0000000..57e0f90
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator.h
@@ -0,0 +1,80 @@
+/*
+ * 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 <unordered_set>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+// Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
+// channel is in use
+class DynamicChannelAllocator {
+ public:
+  DynamicChannelAllocator(Link* link, os::Handler* l2cap_handler) : link_(link), l2cap_handler_(l2cap_handler) {
+    ASSERT(link_ != nullptr);
+    ASSERT(l2cap_handler_ != nullptr);
+  }
+
+  // Allocates a channel. If psm is used, OR the remote cid already exists, return nullptr.
+  // NOTE: The returned DynamicChannelImpl object is still owned by the channel allocator, NOT the client.
+  std::shared_ptr<DynamicChannelImpl> AllocateChannel(Psm psm, Cid remote_cid, SecurityPolicy security_policy);
+
+  std::shared_ptr<DynamicChannelImpl> AllocateReservedChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+                                                              SecurityPolicy security_policy);
+
+  // Gives an unused Cid to be used for opening a channel. If a channel is used, call AllocateReservedChannel. If no
+  // longer needed, use FreeChannel.
+  Cid ReserveChannel();
+
+  // Frees a channel. If psm doesn't exist, it will crash
+  void FreeChannel(Cid cid);
+
+  bool IsPsmUsed(Psm psm) const;
+
+  std::shared_ptr<DynamicChannelImpl> FindChannelByCid(Cid cid);
+  std::shared_ptr<DynamicChannelImpl> FindChannelByRemoteCid(Cid cid);
+
+  // Returns number of open, but not reserved channels
+  size_t NumberOfChannels() const;
+
+  void OnAclDisconnected(hci::ErrorCode hci_status);
+
+ private:
+  Link* link_;
+  os::Handler* l2cap_handler_;
+  std::unordered_set<Cid> used_cid_;
+  std::unordered_map<Cid, std::shared_ptr<DynamicChannelImpl>> channels_;
+  std::unordered_set<Cid> used_remote_cid_;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
new file mode 100644
index 0000000..80d1518
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
@@ -0,0 +1,89 @@
+/*
+ * 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/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using l2cap::internal::testing::MockParameterProvider;
+using l2cap::internal::testing::MockScheduler;
+using testing::MockLink;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capClassicDynamicChannelAllocatorFuzzTest {
+ public:
+  void RunTests(const uint8_t* data, size_t size) {
+    SetUp();
+    TestPrecondition(data, size);
+    TearDown();
+  }
+
+ private:
+  void SetUp() {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+    mock_parameter_provider_ = new NiceMock<MockParameterProvider>();
+    mock_classic_link_ =
+        new NiceMock<MockLink>(handler_, mock_parameter_provider_, std::make_unique<NiceMock<MockAclConnection>>(),
+                               std::make_unique<NiceMock<MockScheduler>>());
+    EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+    channel_allocator_ = std::make_unique<DynamicChannelAllocator>(mock_classic_link_, handler_);
+  }
+
+  void TearDown() {
+    channel_allocator_.reset();
+    delete mock_classic_link_;
+    delete mock_parameter_provider_;
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+  }
+
+  void TestPrecondition(const uint8_t* data, size_t size) {
+    if (size != 2) {
+      return;
+    }
+    Psm psm = *reinterpret_cast<const Psm*>(data);
+    EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+  }
+
+  os::Thread* thread_{nullptr};
+  os::Handler* handler_{nullptr};
+  NiceMock<MockParameterProvider>* mock_parameter_provider_{nullptr};
+  NiceMock<MockLink>* mock_classic_link_{nullptr};
+  std::unique_ptr<DynamicChannelAllocator> channel_allocator_;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
+
+void RunL2capClassicDynamicChannelAllocatorFuzzTest(const uint8_t* data, size_t size) {
+  bluetooth::l2cap::classic::internal::L2capClassicDynamicChannelAllocatorFuzzTest test;
+  test.RunTests(data, size);
+}
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
new file mode 100644
index 0000000..8e3f66b
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
@@ -0,0 +1,94 @@
+/*
+ * 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/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capClassicDynamicChannelAllocatorTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+    mock_parameter_provider_ = new MockParameterProvider();
+    mock_classic_link_ = new MockLink(handler_, mock_parameter_provider_);
+    EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+    channel_allocator_ = std::make_unique<DynamicChannelAllocator>(mock_classic_link_, handler_);
+  }
+
+  void TearDown() override {
+    channel_allocator_.reset();
+    delete mock_classic_link_;
+    delete mock_parameter_provider_;
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_{nullptr};
+  os::Handler* handler_{nullptr};
+  MockParameterProvider* mock_parameter_provider_{nullptr};
+  MockLink* mock_classic_link_{nullptr};
+  std::unique_ptr<DynamicChannelAllocator> channel_allocator_;
+};
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, precondition) {
+  Psm psm = 0x03;
+  EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, allocate_and_free_channel) {
+  Psm psm = 0x03;
+  Cid remote_cid = kFirstDynamicChannel;
+  auto channel = channel_allocator_->AllocateChannel(psm, remote_cid, {});
+  Cid local_cid = channel->GetCid();
+  EXPECT_TRUE(channel_allocator_->IsPsmUsed(psm));
+  EXPECT_EQ(channel, channel_allocator_->FindChannelByCid(local_cid));
+  ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(local_cid));
+  EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, reserve_channel) {
+  Psm psm = 0x03;
+  Cid remote_cid = kFirstDynamicChannel;
+  Cid reserved = channel_allocator_->ReserveChannel();
+  auto channel = channel_allocator_->AllocateReservedChannel(reserved, psm, remote_cid, {});
+  Cid local_cid = channel->GetCid();
+  EXPECT_EQ(local_cid, reserved);
+  EXPECT_TRUE(channel_allocator_->IsPsmUsed(psm));
+  EXPECT_EQ(channel, channel_allocator_->FindChannelByCid(local_cid));
+  ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(local_cid));
+  EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
new file mode 100644
index 0000000..c0614f9
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
@@ -0,0 +1,121 @@
+/*
+ * 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/sender.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+DynamicChannelImpl::DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler)
+    : psm_(psm), cid_(cid), remote_cid_(remote_cid), link_(link), l2cap_handler_(l2cap_handler),
+      device_(link->GetDevice()) {
+  ASSERT(IsPsmValid(psm_));
+  ASSERT(cid_ > 0);
+  ASSERT(remote_cid_ > 0);
+  ASSERT(link_ != nullptr);
+  ASSERT(l2cap_handler_ != nullptr);
+}
+
+hci::Address DynamicChannelImpl::GetDevice() const {
+  return device_;
+}
+
+void DynamicChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+                                                 DynamicChannel::OnCloseCallback on_close_callback) {
+  ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+  // If channel is already closed, call the callback immediately without saving it
+  if (closed_) {
+    user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+    return;
+  }
+  user_handler_ = user_handler;
+  on_close_callback_ = std::move(on_close_callback);
+}
+
+void DynamicChannelImpl::Close() {
+  link_->SendDisconnectionRequest(cid_, remote_cid_);
+}
+
+void DynamicChannelImpl::OnClosed(hci::ErrorCode status) {
+  ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+             cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+  closed_ = true;
+  close_reason_ = status;
+  link_ = nullptr;
+  l2cap_handler_ = nullptr;
+  if (user_handler_ == nullptr) {
+    return;
+  }
+  // On close callback can only be called once
+  user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+  user_handler_ = nullptr;
+  on_close_callback_.Reset();
+}
+
+std::string DynamicChannelImpl::ToString() {
+  std::ostringstream ss;
+  ss << "Device " << device_ << "Psm 0x" << std::hex << psm_ << " Cid 0x" << std::hex << cid_;
+  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;
+}
+
+void DynamicChannelImpl::SetSender(l2cap::internal::Sender* sender) {
+  sender_ = sender;
+}
+
+void DynamicChannelImpl::SetIncomingMtu(Mtu mtu) {
+  sender_->SetIncomingMtu(mtu);
+}
+
+void DynamicChannelImpl::SetRetransmissionFlowControlConfig(
+    const RetransmissionAndFlowControlConfigurationOption& option) {
+  sender_->SetChannelRetransmissionFlowControlMode(option);
+}
+
+void DynamicChannelImpl::SetFcsType(FcsType fcs_type) {
+  sender_->SetFcsType(fcs_type);
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h
new file mode 100644
index 0000000..95be5c7
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h
@@ -0,0 +1,123 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+class DynamicChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+  DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler);
+
+  virtual ~DynamicChannelImpl() = default;
+
+  hci::Address GetDevice() const;
+
+  virtual void RegisterOnCloseCallback(os::Handler* user_handler, DynamicChannel::OnCloseCallback on_close_callback);
+
+  virtual void Close();
+  virtual void OnClosed(hci::ErrorCode status);
+  virtual std::string ToString();
+
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+    return channel_queue_.GetUpEnd();
+  }
+
+  common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+    return channel_queue_.GetDownEnd();
+  }
+
+  virtual Cid GetCid() const {
+    return cid_;
+  }
+
+  virtual Cid GetRemoteCid() const {
+    return remote_cid_;
+  }
+
+  virtual Psm GetPsm() const {
+    return psm_;
+  }
+
+  enum class ConfigurationStatus { NOT_CONFIGURED, CONFIGURED };
+
+  virtual ConfigurationStatus GetOutgoingConfigurationStatus() const;
+  virtual void SetOutgoingConfigurationStatus(ConfigurationStatus status);
+
+  virtual ConfigurationStatus GetIncomingConfigurationStatus() const;
+  virtual void SetIncomingConfigurationStatus(ConfigurationStatus status);
+
+  /**
+   * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
+   * configuration to Sender
+   */
+  void SetSender(l2cap::internal::Sender* sender) override;
+
+  virtual void SetIncomingMtu(Mtu mtu);
+
+  virtual void SetRetransmissionFlowControlConfig(const RetransmissionAndFlowControlConfigurationOption& mode);
+
+  virtual void SetFcsType(FcsType fcs_type);
+
+  // TODO(cmanton) Do something a little bit better than this
+  bool local_initiated_{false};
+
+ private:
+  const Psm psm_;
+  const Cid cid_;
+  const Cid remote_cid_;
+  Link* link_;
+  os::Handler* l2cap_handler_;
+  const hci::Address device_;
+
+  // User supported states
+  os::Handler* user_handler_ = nullptr;
+  DynamicChannel::OnCloseCallback on_close_callback_{};
+
+  // Internal states
+  bool closed_ = false;
+  hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+  static constexpr size_t kChannelQueueSize = 10;
+  common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+      kChannelQueueSize};
+  ConfigurationStatus outgoing_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
+  ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
+
+  l2cap::internal::Sender* sender_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl);
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc b/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
new file mode 100644
index 0000000..2f6c649
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
@@ -0,0 +1,164 @@
+/*
+ * 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/classic/internal/dynamic_channel_impl.h"
+
+#include "common/testing/bind_test_util.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capClassicDynamicChannelImplTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicDynamicChannelImplTest, get_device) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+                                          l2cap_handler_);
+  EXPECT_EQ(device, dynamic_channel_impl.GetDevice());
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, close_triggers_callback) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+                                          l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  dynamic_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, register_callback_after_close_should_call_immediately) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+                                          l2cap_handler_);
+
+  // Channel closure should do nothing
+  dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+  // Register on close callback should trigger callback immediately
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  dynamic_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, close_twice_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+                                          l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  dynamic_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  // 2nd OnClose() callback should fail
+  EXPECT_DEATH(dynamic_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, multiple_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+                                          l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  dynamic_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  EXPECT_DEATH(dynamic_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+                                                            common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+               ".*RegisterOnCloseCallback.*");
+
+  user_handler->Clear();
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_impl.h b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
new file mode 100644
index 0000000..2fcf3fc
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
@@ -0,0 +1,68 @@
+/*
+ * 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 "common/bind.h"
+
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+class DynamicChannelServiceImpl {
+ public:
+  virtual ~DynamicChannelServiceImpl() = default;
+
+  struct PendingRegistration {
+    os::Handler* user_handler_ = nullptr;
+    DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+    DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+    DynamicChannelConfigurationOption configuration_;
+  };
+
+  virtual void NotifyChannelCreation(std::unique_ptr<DynamicChannel> channel) {
+    user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+  }
+
+  DynamicChannelConfigurationOption GetConfigOption() const {
+    return config_option_;
+  }
+
+  friend class DynamicChannelServiceManagerImpl;
+
+ protected:
+  // protected access for mocking
+  DynamicChannelServiceImpl(os::Handler* user_handler,
+                            DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback,
+                            DynamicChannelConfigurationOption config_option)
+      : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)),
+        config_option_(config_option) {}
+
+ private:
+  os::Handler* user_handler_ = nullptr;
+  DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+  DynamicChannelConfigurationOption config_option_;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc
new file mode 100644
index 0000000..a44a72e
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc
@@ -0,0 +1,82 @@
+/*
+ * 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/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/psm.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void DynamicChannelServiceManagerImpl::Register(Psm psm,
+                                                DynamicChannelServiceImpl::PendingRegistration pending_registration) {
+  if (!IsPsmValid(psm)) {
+    std::unique_ptr<DynamicChannelService> invalid_service(new DynamicChannelService());
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+  } else if (IsServiceRegistered(psm)) {
+    std::unique_ptr<DynamicChannelService> invalid_service(new DynamicChannelService());
+    pending_registration.user_handler_->Post(common::BindOnce(
+        std::move(pending_registration.on_registration_complete_callback_),
+        DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+  } else {
+    service_map_.try_emplace(psm,
+                             DynamicChannelServiceImpl(pending_registration.user_handler_,
+                                                       std::move(pending_registration.on_connection_open_callback_),
+                                                       pending_registration.configuration_));
+    std::unique_ptr<DynamicChannelService> user_service(new DynamicChannelService(psm, this, l2cap_layer_handler_));
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         DynamicChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+  }
+}
+
+void DynamicChannelServiceManagerImpl::Unregister(Psm psm, DynamicChannelService::OnUnregisteredCallback callback,
+                                                  os::Handler* handler) {
+  if (IsServiceRegistered(psm)) {
+    service_map_.erase(psm);
+    handler->Post(std::move(callback));
+  } else {
+    LOG_ERROR("service not registered psm:%d", psm);
+  }
+}
+
+bool DynamicChannelServiceManagerImpl::IsServiceRegistered(Psm psm) const {
+  return service_map_.find(psm) != service_map_.end();
+}
+
+DynamicChannelServiceImpl* DynamicChannelServiceManagerImpl::GetService(Psm psm) {
+  ASSERT(IsServiceRegistered(psm));
+  return &service_map_.find(psm)->second;
+}
+
+std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> DynamicChannelServiceManagerImpl::GetRegisteredServices() {
+  std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> results;
+  for (auto& elem : service_map_) {
+    results.emplace_back(elem.first, &elem.second);
+  }
+  return results;
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h
new file mode 100644
index 0000000..c980639
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h
@@ -0,0 +1,54 @@
+/*
+ * 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 "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class DynamicChannelServiceManagerImpl {
+ public:
+  explicit DynamicChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+      : l2cap_layer_handler_(l2cap_layer_handler) {}
+
+  virtual ~DynamicChannelServiceManagerImpl() = default;
+  //
+  // All APIs must be invoked in L2CAP layer handler
+  //
+  virtual void Register(Psm psm, DynamicChannelServiceImpl::PendingRegistration pending_registration);
+  virtual void Unregister(Psm psm, DynamicChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+  virtual bool IsServiceRegistered(Psm psm) const;
+  virtual DynamicChannelServiceImpl* GetService(Psm psm);
+
+  virtual std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> GetRegisteredServices();
+ private:
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  std::unordered_map<Psm, DynamicChannelServiceImpl> service_map_;
+};
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..34363f1
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
@@ -0,0 +1,46 @@
+/*
+ * 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 "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockDynamicChannelServiceManagerImpl : public DynamicChannelServiceManagerImpl {
+ public:
+  MockDynamicChannelServiceManagerImpl() : DynamicChannelServiceManagerImpl(nullptr) {}
+  MOCK_METHOD(void, Register, (Psm psm, DynamicChannelServiceImpl::PendingRegistration pending_registration),
+              (override));
+  MOCK_METHOD(void, Unregister, (Psm psm, DynamicChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+              (override));
+  MOCK_METHOD(bool, IsServiceRegistered, (Psm psm), (const, override));
+  MOCK_METHOD(DynamicChannelServiceImpl*, GetService, (Psm psm), (override));
+  MOCK_METHOD((std::vector<std::pair<Psm, DynamicChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc b/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc
new file mode 100644
index 0000000..f59dcb6
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 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 <future>
+
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class L2capDynamicServiceManagerTest : public ::testing::Test {
+ public:
+  ~L2capDynamicServiceManagerTest() override = default;
+
+  void OnServiceRegistered(bool expect_success, DynamicChannelManager::RegistrationResult result,
+                           std::unique_ptr<DynamicChannelService> user_service) {
+    EXPECT_EQ(result == DynamicChannelManager::RegistrationResult::SUCCESS, expect_success);
+    service_registered_ = expect_success;
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    user_handler_ = new os::Handler(thread_);
+    l2cap_handler_ = new os::Handler(thread_);
+    manager_ = new DynamicChannelServiceManagerImpl{l2cap_handler_};
+  }
+
+  void TearDown() override {
+    delete manager_;
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    user_handler_->Clear();
+    delete user_handler_;
+    delete thread_;
+  }
+
+  void sync_user_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+  DynamicChannelServiceManagerImpl* manager_ = nullptr;
+  os::Thread* thread_ = nullptr;
+  os::Handler* user_handler_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+
+  bool service_registered_ = false;
+};
+
+TEST_F(L2capDynamicServiceManagerTest, register_and_unregister_classic_dynamic_channel) {
+  DynamicChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capDynamicServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+  Cid cid = kSmpBrCid;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_TRUE(service_registered_);
+  manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capDynamicServiceManagerTest, register_classic_dynamic_channel_bad_cid) {
+  DynamicChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capDynamicServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+  Cid cid = 0x1000;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_FALSE(service_registered_);
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.cc b/gd/l2cap/classic/internal/fixed_channel_impl.cc
new file mode 100644
index 0000000..8ac6c94
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.cc
@@ -0,0 +1,102 @@
+/*
+ * 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+FixedChannelImpl::FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler)
+    : cid_(cid), device_(link->GetDevice()), link_(link), l2cap_handler_(l2cap_handler) {
+  ASSERT_LOG(cid_ >= kFirstFixedChannel && cid_ <= kLastFixedChannel, "Invalid cid: %d", cid_);
+  ASSERT(link_ != nullptr);
+  ASSERT(l2cap_handler_ != nullptr);
+}
+
+void FixedChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+                                               FixedChannel::OnCloseCallback on_close_callback) {
+  ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+  // If channel is already closed, call the callback immediately without saving it
+  if (closed_) {
+    user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+    return;
+  }
+  user_handler_ = user_handler;
+  on_close_callback_ = std::move(on_close_callback);
+}
+
+void FixedChannelImpl::OnClosed(hci::ErrorCode status) {
+  ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+             cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+  closed_ = true;
+  close_reason_ = status;
+  acquired_ = false;
+  link_ = nullptr;
+  l2cap_handler_ = nullptr;
+  if (user_handler_ == nullptr) {
+    return;
+  }
+  // On close callback can only be called once
+  user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+  user_handler_ = nullptr;
+  on_close_callback_.Reset();
+}
+
+void FixedChannelImpl::Acquire() {
+  ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+  if (closed_) {
+    LOG_WARN("%s is already closed", ToString().c_str());
+    ASSERT(!acquired_);
+    return;
+  }
+  if (acquired_) {
+    LOG_DEBUG("%s was already acquired", ToString().c_str());
+    return;
+  }
+  acquired_ = true;
+  link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::Release() {
+  ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+  if (closed_) {
+    LOG_WARN("%s is already closed", ToString().c_str());
+    ASSERT(!acquired_);
+    return;
+  }
+  if (!acquired_) {
+    LOG_DEBUG("%s was already released", ToString().c_str());
+    return;
+  }
+  acquired_ = false;
+  link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.h b/gd/l2cap/classic/internal/fixed_channel_impl.h
new file mode 100644
index 0000000..6fde5c6
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.h
@@ -0,0 +1,107 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+  FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
+
+  virtual ~FixedChannelImpl() = default;
+
+  hci::Address GetDevice() const {
+    return device_;
+  }
+
+  virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
+
+  virtual void Acquire();
+
+  virtual void Release();
+
+  virtual bool IsAcquired() const {
+    return acquired_;
+  }
+
+  virtual void OnClosed(hci::ErrorCode status);
+
+  virtual std::string ToString() {
+    std::ostringstream ss;
+    ss << "Device " << device_ << " Cid 0x" << std::hex << cid_;
+    return ss.str();
+  }
+
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+    return channel_queue_.GetUpEnd();
+  }
+
+  common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+    return channel_queue_.GetDownEnd();
+  }
+
+  Cid GetCid() const {
+    return cid_;
+  }
+
+  Cid GetRemoteCid() const {
+    return cid_;
+  }
+  void SetSender(l2cap::internal::Sender* sender) override;
+
+ private:
+  // Constructor states
+  // For logging purpose only
+  const Cid cid_;
+  // For logging purpose only
+  const hci::Address device_;
+  // Needed to handle Acquire() and Release()
+  Link* link_;
+  os::Handler* l2cap_handler_;
+
+  // User supported states
+  os::Handler* user_handler_ = nullptr;
+  FixedChannel::OnCloseCallback on_close_callback_{};
+
+  // Internal states
+  bool acquired_ = false;
+  bool closed_ = false;
+  hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+  static constexpr size_t kChannelQueueSize = 10;
+  common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+      kChannelQueueSize};
+
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelImpl);
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_impl_mock.h
new file mode 100644
index 0000000..680bf51
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl_mock.h
@@ -0,0 +1,44 @@
+/*
+ * 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 "l2cap/classic/internal/fixed_channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelImpl : public FixedChannelImpl {
+ public:
+  MockFixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler) : FixedChannelImpl(cid, link, l2cap_handler) {}
+  MOCK_METHOD(void, RegisterOnCloseCallback,
+              (os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
+  MOCK_METHOD(void, Acquire, (), (override));
+  MOCK_METHOD(void, Release, (), (override));
+  MOCK_METHOD(bool, IsAcquired, (), (override, const));
+  MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl_test.cc b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
new file mode 100644
index 0000000..750473d
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
@@ -0,0 +1,231 @@
+/*
+ * 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/classic/internal/fixed_channel_impl.h"
+
+#include "common/testing/bind_test_util.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capClassicFixedChannelImplTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicFixedChannelImplTest, get_device) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+  EXPECT_EQ(device, fixed_channel_impl.GetDevice());
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, close_triggers_callback) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, register_callback_after_close_should_call_immediately) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Channel closure should do nothing
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+  // Register on close callback should trigger callback immediately
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, close_twice_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  // 2nd OnClose() callback should fail
+  EXPECT_DEATH(fixed_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, multiple_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  EXPECT_DEATH(fixed_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+                                                          common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+               ".*RegisterOnCloseCallback.*");
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, call_acquire_before_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+  EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, call_release_before_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+  EXPECT_DEATH(fixed_channel_impl.Release(), ".*Release.*");
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, test_acquire_release_channel) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Default should be false
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+  // Should be called 2 times after Acquire() and Release()
+  EXPECT_CALL(mock_classic_link, RefreshRefCount()).Times(2);
+
+  fixed_channel_impl.Acquire();
+  EXPECT_TRUE(fixed_channel_impl.IsAcquired());
+
+  fixed_channel_impl.Release();
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, test_acquire_after_close) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  // Release or Acquire after closing should crash
+  EXPECT_CALL(mock_classic_link, RefreshRefCount()).Times(0);
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+  EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+
+  user_handler->Clear();
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_impl.h b/gd/l2cap/classic/internal/fixed_channel_service_impl.h
new file mode 100644
index 0000000..b06983f
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_impl.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "l2cap/classic/fixed_channel.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/fixed_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class FixedChannelServiceImpl {
+ public:
+  virtual ~FixedChannelServiceImpl() = default;
+
+  struct PendingRegistration {
+    os::Handler* user_handler_ = nullptr;
+    FixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+    FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+  };
+
+  virtual void NotifyChannelCreation(std::unique_ptr<FixedChannel> channel) {
+    user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+  }
+
+  friend class FixedChannelServiceManagerImpl;
+
+ protected:
+  // protected access for mocking
+  FixedChannelServiceImpl(os::Handler* user_handler,
+                          FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback)
+      : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)) {}
+
+ private:
+  os::Handler* user_handler_ = nullptr;
+  FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h
new file mode 100644
index 0000000..7aeb094
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h
@@ -0,0 +1,40 @@
+/*
+ * 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 "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceImpl : public FixedChannelServiceImpl {
+ public:
+  MockFixedChannelServiceImpl() : FixedChannelServiceImpl(nullptr, FixedChannelManager::OnConnectionOpenCallback()) {}
+  MOCK_METHOD(void, NotifyChannelCreation, (std::unique_ptr<FixedChannel> channel), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc
new file mode 100644
index 0000000..b557970
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc
@@ -0,0 +1,107 @@
+/*
+ * 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/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void FixedChannelServiceManagerImpl::Register(Cid cid,
+                                              FixedChannelServiceImpl::PendingRegistration pending_registration) {
+  if (cid < kFirstFixedChannel || cid > kLastFixedChannel || cid == kClassicSignallingCid) {
+    std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+  } else if (IsServiceRegistered(cid)) {
+    std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+  } else {
+    service_map_.try_emplace(cid,
+                             FixedChannelServiceImpl(pending_registration.user_handler_,
+                                                     std::move(pending_registration.on_connection_open_callback_)));
+    std::unique_ptr<FixedChannelService> user_service(new FixedChannelService(cid, this, l2cap_layer_handler_));
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+  }
+}
+
+void FixedChannelServiceManagerImpl::Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback,
+                                                os::Handler* handler) {
+  if (IsServiceRegistered(cid)) {
+    service_map_.erase(cid);
+    handler->Post(std::move(callback));
+  } else {
+    LOG_ERROR("service not registered cid:%d", cid);
+  }
+}
+
+bool FixedChannelServiceManagerImpl::IsServiceRegistered(Cid cid) const {
+  return service_map_.find(cid) != service_map_.end();
+}
+
+FixedChannelServiceImpl* FixedChannelServiceManagerImpl::GetService(Cid cid) {
+  ASSERT(IsServiceRegistered(cid));
+  return &service_map_.find(cid)->second;
+}
+
+std::vector<std::pair<Cid, FixedChannelServiceImpl*>> FixedChannelServiceManagerImpl::GetRegisteredServices() {
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  for (auto& elem : service_map_) {
+    results.emplace_back(elem.first, &elem.second);
+  }
+  return results;
+}
+
+namespace {
+constexpr uint64_t kSignallingChannelMask = 0x02;
+constexpr uint64_t kConnectionlessReceptionMask = 0x04;
+constexpr uint64_t kBrEdrSecurityManager = 0x80;
+}  // namespace
+
+uint64_t FixedChannelServiceManagerImpl::GetSupportedFixedChannelMask() {
+  uint64_t result = 0;
+  result |= kSignallingChannelMask;  // Signalling channel is mandatory
+  for (const auto& elem : service_map_) {
+    Cid cid = elem.first;
+    switch (cid) {
+      case kConnectionlessCid:
+        result |= kConnectionlessReceptionMask;
+        continue;
+      case kSmpBrCid:
+        result |= kBrEdrSecurityManager;
+        continue;
+      default:
+        LOG_WARN("Unknown fixed channel is registered: 0x%x", cid);
+        continue;
+    }
+  }
+  return result;
+}
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h
new file mode 100644
index 0000000..1e1d21d
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class FixedChannelServiceManagerImpl {
+ public:
+  explicit FixedChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+      : l2cap_layer_handler_(l2cap_layer_handler) {}
+  virtual ~FixedChannelServiceManagerImpl() = default;
+
+  // All APIs must be invoked in L2CAP layer handler
+
+  virtual void Register(Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration);
+  virtual void Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+  virtual bool IsServiceRegistered(Cid cid) const;
+  virtual FixedChannelServiceImpl* GetService(Cid cid);
+  virtual std::vector<std::pair<Cid, FixedChannelServiceImpl*>> GetRegisteredServices();
+  virtual uint64_t GetSupportedFixedChannelMask();
+
+ private:
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  std::unordered_map<Cid, FixedChannelServiceImpl> service_map_;
+};
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..55aa4cf
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h
@@ -0,0 +1,45 @@
+/*
+ * 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 "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceManagerImpl : public FixedChannelServiceManagerImpl {
+ public:
+  MockFixedChannelServiceManagerImpl() : FixedChannelServiceManagerImpl(nullptr) {}
+  MOCK_METHOD(void, Register, (Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration), (override));
+  MOCK_METHOD(void, Unregister, (Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+              (override));
+  MOCK_METHOD(bool, IsServiceRegistered, (Cid cid), (const, override));
+  MOCK_METHOD(FixedChannelServiceImpl*, GetService, (Cid cid), (override));
+  MOCK_METHOD((std::vector<std::pair<Cid, FixedChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc b/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc
new file mode 100644
index 0000000..d586913
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 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/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class L2capClassicFixedServiceManagerTest : public ::testing::Test {
+ public:
+  ~L2capClassicFixedServiceManagerTest() override = default;
+
+  void OnServiceRegistered(bool expect_success, FixedChannelManager::RegistrationResult result,
+                           std::unique_ptr<FixedChannelService> user_service) {
+    EXPECT_EQ(result == FixedChannelManager::RegistrationResult::SUCCESS, expect_success);
+    service_registered_ = expect_success;
+  }
+
+ protected:
+  void SetUp() override {
+    manager_ = new FixedChannelServiceManagerImpl{nullptr};
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    user_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    user_handler_->Clear();
+    delete user_handler_;
+    delete thread_;
+    delete manager_;
+  }
+
+  void sync_user_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+  FixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Thread* thread_ = nullptr;
+  os::Handler* user_handler_ = nullptr;
+
+  bool service_registered_ = false;
+};
+
+TEST_F(L2capClassicFixedServiceManagerTest, register_and_unregister_classic_fixed_channel) {
+  FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capClassicFixedServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+  Cid cid = kSmpBrCid;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_TRUE(service_registered_);
+  manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capClassicFixedServiceManagerTest, register_classic_fixed_channel_bad_cid) {
+  FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capClassicFixedServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+  Cid cid = 0x1000;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_FALSE(service_registered_);
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
new file mode 100644
index 0000000..7b5178f
--- /dev/null
+++ b/gd/l2cap/classic/internal/link.cc
@@ -0,0 +1,187 @@
+/*
+ * 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 <chrono>
+#include <memory>
+
+#include "hci/acl_manager.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "os/alarm.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+           std::unique_ptr<l2cap::internal::Scheduler> scheduler,
+           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)),
+      receiver_(acl_connection_->GetAclQueueEnd(), l2cap_handler_, scheduler_.get()),
+      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_,
+                          fixed_service_manager_) {
+  ASSERT(l2cap_handler_ != nullptr);
+  ASSERT(acl_connection_ != nullptr);
+  ASSERT(scheduler_ != nullptr);
+  ASSERT(parameter_provider_ != nullptr);
+  link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+                                       parameter_provider_->GetClassicLinkIdleDisconnectTimeout());
+}
+
+void Link::OnAclDisconnected(hci::ErrorCode status) {
+  fixed_channel_allocator_.OnAclDisconnected(status);
+  dynamic_channel_allocator_.OnAclDisconnected(status);
+}
+
+void Link::Disconnect() {
+  acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+}
+
+std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
+  auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
+  scheduler_->AttachChannel(cid, channel);
+  return channel;
+}
+
+bool Link::IsFixedChannelAllocated(Cid cid) {
+  return fixed_channel_allocator_.IsChannelAllocated(cid);
+}
+
+Cid Link::ReserveDynamicChannel() {
+  return dynamic_channel_allocator_.ReserveChannel();
+}
+
+void Link::SendConnectionRequest(Psm psm, Cid local_cid) {
+  signalling_manager_.SendConnectionRequest(psm, local_cid);
+}
+
+void Link::SendConnectionRequest(Psm psm, Cid local_cid,
+                                 PendingDynamicChannelConnection pending_dynamic_channel_connection) {
+  local_cid_to_pending_dynamic_channel_connection_map_[local_cid] = std::move(pending_dynamic_channel_connection);
+  signalling_manager_.SendConnectionRequest(psm, local_cid);
+}
+
+void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+  signalling_manager_.SendDisconnectionRequest(local_cid, remote_cid);
+}
+
+void Link::SendInformationRequest(InformationRequestInfoType type) {
+  signalling_manager_.SendInformationRequest(type);
+}
+
+std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
+                                                                 SecurityPolicy security_policy) {
+  auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
+  if (channel != nullptr) {
+    scheduler_->AttachChannel(channel->GetCid(), channel);
+  }
+  channel->local_initiated_ = false;
+  return channel;
+}
+
+std::shared_ptr<DynamicChannelImpl> Link::AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+                                                                         SecurityPolicy security_policy) {
+  auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
+  if (channel != nullptr) {
+    scheduler_->AttachChannel(channel->GetCid(), channel);
+  }
+  channel->local_initiated_ = true;
+  return channel;
+}
+
+classic::DynamicChannelConfigurationOption Link::GetConfigurationForInitialConfiguration(Cid cid) {
+  ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+         local_cid_to_pending_dynamic_channel_connection_map_.end());
+  return local_cid_to_pending_dynamic_channel_connection_map_[cid].configuration_;
+}
+
+void Link::FreeDynamicChannel(Cid cid) {
+  if (dynamic_channel_allocator_.FindChannelByCid(cid) == nullptr) {
+    return;
+  }
+  scheduler_->DetachChannel(cid);
+  dynamic_channel_allocator_.FreeChannel(cid);
+}
+
+void Link::RefreshRefCount() {
+  int ref_count = 0;
+  ref_count += fixed_channel_allocator_.GetRefCount();
+  ref_count += dynamic_channel_allocator_.NumberOfChannels();
+  ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
+  if (ref_count > 0) {
+    link_idle_disconnect_alarm_.Cancel();
+  } else {
+    link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+                                         parameter_provider_->GetClassicLinkIdleDisconnectTimeout());
+  }
+}
+
+void Link::NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> user_channel) {
+  ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+         local_cid_to_pending_dynamic_channel_connection_map_.end());
+  auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
+  pending_dynamic_channel_connection.handler_->Post(
+      common::BindOnce(std::move(pending_dynamic_channel_connection.on_open_callback_), std::move(user_channel)));
+  local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
+}
+
+void Link::NotifyChannelFail(Cid cid) {
+  ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+         local_cid_to_pending_dynamic_channel_connection_map_.end());
+  auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
+  // TODO(cmanton) Pass proper connection falure result to user
+  DynamicChannelManager::ConnectionResult result;
+  pending_dynamic_channel_connection.handler_->Post(
+      common::BindOnce(std::move(pending_dynamic_channel_connection.on_fail_callback_), result));
+  local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
+}
+
+void Link::SetRemoteConnectionlessMtu(Mtu mtu) {
+  remote_mtu_ = mtu;
+}
+
+Mtu Link::GetRemoteConnectionlessMtu() const {
+  return remote_mtu_;
+}
+
+void Link::SetRemoteSupportsErtm(bool supported) {
+  remote_supports_ertm_ = supported;
+}
+
+bool Link::GetRemoteSupportsErtm() const {
+  return remote_supports_ertm_;
+}
+
+void Link::SetRemoteSupportsFcs(bool supported) {
+  remote_supports_fcs_ = supported;
+}
+
+bool Link::GetRemoteSupportsFcs() const {
+  return remote_supports_fcs_;
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
new file mode 100644
index 0000000..2c6c1b8
--- /dev/null
+++ b/gd/l2cap/classic/internal/link.h
@@ -0,0 +1,132 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#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/receiver.h"
+#include "l2cap/internal/scheduler.h"
+#include "os/alarm.h"
+#include "os/handler.h"
+#include "signalling_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link {
+ public:
+  Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+       std::unique_ptr<l2cap::internal::Scheduler> scheduler, l2cap::internal::ParameterProvider* parameter_provider,
+       DynamicChannelServiceManagerImpl* dynamic_service_manager,
+       FixedChannelServiceManagerImpl* fixed_service_manager);
+
+  virtual ~Link() = default;
+
+  virtual hci::Address GetDevice() {
+    return acl_connection_->GetAddress();
+  }
+
+  struct PendingDynamicChannelConnection {
+    os::Handler* handler_;
+    DynamicChannelManager::OnConnectionOpenCallback on_open_callback_;
+    DynamicChannelManager::OnConnectionFailureCallback on_fail_callback_;
+    classic::DynamicChannelConfigurationOption configuration_;
+  };
+
+  // ACL methods
+
+  virtual void OnAclDisconnected(hci::ErrorCode status);
+
+  virtual void Disconnect();
+
+  // FixedChannel methods
+
+  std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
+
+  virtual bool IsFixedChannelAllocated(Cid cid);
+
+  // DynamicChannel methods
+
+  virtual Cid ReserveDynamicChannel();
+
+  virtual void SendConnectionRequest(Psm psm, Cid local_cid);
+  virtual void SendConnectionRequest(Psm psm, Cid local_cid,
+                                     PendingDynamicChannelConnection pending_dynamic_channel_connection);
+
+  virtual void SendInformationRequest(InformationRequestInfoType type);
+
+  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+
+  virtual std::shared_ptr<DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
+                                                                     SecurityPolicy security_policy);
+
+  virtual std::shared_ptr<DynamicChannelImpl> AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+                                                                             SecurityPolicy security_policy);
+
+  virtual classic::DynamicChannelConfigurationOption GetConfigurationForInitialConfiguration(Cid cid);
+
+  virtual void FreeDynamicChannel(Cid cid);
+
+  // Check how many channels are acquired or in use, if zero, start tear down timer, if non-zero, cancel tear down timer
+  virtual void RefreshRefCount();
+
+  virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel);
+  virtual void NotifyChannelFail(Cid cid);
+
+  // Information received from signalling channel
+  virtual void SetRemoteConnectionlessMtu(Mtu mtu);
+  virtual Mtu GetRemoteConnectionlessMtu() const;
+  virtual void SetRemoteSupportsErtm(bool supported);
+  virtual bool GetRemoteSupportsErtm() const;
+  virtual void SetRemoteSupportsFcs(bool supported);
+  virtual bool GetRemoteSupportsFcs() const;
+
+ private:
+  os::Handler* l2cap_handler_;
+  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_;
+  std::unique_ptr<l2cap::internal::Scheduler> scheduler_;
+  l2cap::internal::Receiver receiver_;
+  l2cap::internal::ParameterProvider* parameter_provider_;
+  DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+  FixedChannelServiceManagerImpl* fixed_service_manager_;
+  ClassicSignallingManager signalling_manager_;
+  std::unordered_map<Cid, PendingDynamicChannelConnection> local_cid_to_pending_dynamic_channel_connection_map_;
+  os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
+  Mtu remote_mtu_ = kMinimumClassicMtu;
+  bool remote_supports_ertm_ = false;
+  bool remote_supports_fcs_ = false;
+  DISALLOW_COPY_AND_ASSIGN(Link);
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager.cc b/gd/l2cap/classic/internal/link_manager.cc
new file mode 100644
index 0000000..ee93fd7
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager.cc
@@ -0,0 +1,191 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/scheduler_fifo.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void LinkManager::ConnectFixedChannelServices(hci::Address device,
+                                              PendingFixedChannelConnection pending_fixed_channel_connection) {
+  // Check if there is any service registered
+  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
+  if (fixed_channel_services.empty()) {
+    // If so, return error
+    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+        std::move(pending_fixed_channel_connection.on_fail_callback_),
+        FixedChannelManager::ConnectionResult{
+            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
+    return;
+  }
+  // Otherwise, check if device has an ACL connection
+  auto* link = GetLink(device);
+  if (link != nullptr) {
+    // If device already have an ACL connection
+    // Check if all registered services have an allocated channel and allocate one if not already allocated
+    int num_new_channels = 0;
+    for (auto& fixed_channel_service : fixed_channel_services) {
+      if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
+        // This channel is already allocated for this link, do not allocated twice
+        continue;
+      }
+      // Allocate channel for newly registered fixed channels
+      auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+      fixed_channel_service.second->NotifyChannelCreation(
+          std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+      num_new_channels++;
+    }
+    // Declare connection failure if no new channels are created
+    if (num_new_channels == 0) {
+      pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+          std::move(pending_fixed_channel_connection.on_fail_callback_),
+          FixedChannelManager::ConnectionResult{
+              .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
+    }
+    // No need to create ACL connection, return without saving any pending connections
+    return;
+  }
+  // If not, create new ACL connection
+  // Add request to pending link list first
+  auto pending_link = pending_links_.find(device);
+  if (pending_link == pending_links_.end()) {
+    // Create pending link if not exist
+    pending_links_.try_emplace(device);
+    pending_link = pending_links_.find(device);
+  }
+  pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
+  // Then create new ACL connection
+  acl_manager_->CreateConnection(device);
+}
+
+void LinkManager::ConnectDynamicChannelServices(
+    hci::Address device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) {
+  auto* link = GetLink(device);
+  if (link == nullptr) {
+    acl_manager_->CreateConnection(device);
+    if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) {
+      pending_dynamic_channels_[device].push_back(psm);
+      pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection));
+    } else {
+      pending_dynamic_channels_[device] = {psm};
+      pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection));
+    }
+    return;
+  }
+  link->SendConnectionRequest(psm, link->ReserveDynamicChannel(), std::move(pending_dynamic_channel_connection));
+}
+
+Link* LinkManager::GetLink(const hci::Address device) {
+  if (links_.find(device) == links_.end()) {
+    return nullptr;
+  }
+  return &links_.find(device)->second;
+}
+
+void LinkManager::OnConnectSuccess(std::unique_ptr<hci::AclConnection> acl_connection) {
+  // Same link should not be connected twice
+  hci::Address device = acl_connection->GetAddress();
+  ASSERT_LOG(GetLink(device) == nullptr, "%s is connected twice without disconnection",
+             acl_connection->GetAddress().ToString().c_str());
+  // Register ACL disconnection callback in LinkManager so that we can clean up link resource properly
+  acl_connection->RegisterDisconnectCallback(
+      common::BindOnce(&LinkManager::OnDisconnect, common::Unretained(this), device), l2cap_handler_);
+  auto* link_queue_up_end = acl_connection->GetAclQueueEnd();
+  links_.try_emplace(device, l2cap_handler_, std::move(acl_connection),
+                     std::make_unique<l2cap::internal::Fifo>(link_queue_up_end, l2cap_handler_), parameter_provider_,
+                     dynamic_channel_service_manager_, fixed_channel_service_manager_);
+  auto* link = GetLink(device);
+  ASSERT(link != nullptr);
+  link->SendInformationRequest(InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED);
+  link->SendInformationRequest(InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED);
+
+  // Allocate and distribute channels for all registered fixed channel services
+  auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
+  for (auto& fixed_channel_service : fixed_channel_services) {
+    auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+    fixed_channel_service.second->NotifyChannelCreation(
+        std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+  }
+  if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) {
+    for (Psm psm : pending_dynamic_channels_[device]) {
+      auto& callbacks = pending_dynamic_channels_callbacks_[device].front();
+      link->SendConnectionRequest(psm, link->ReserveDynamicChannel(), std::move(callbacks));
+      pending_dynamic_channels_callbacks_[device].pop_front();
+    }
+    pending_dynamic_channels_.erase(device);
+    pending_dynamic_channels_callbacks_.erase(device);
+  }
+  // Remove device from pending links list, if any
+  auto pending_link = pending_links_.find(device);
+  if (pending_link == pending_links_.end()) {
+    // This an incoming connection, exit
+    return;
+  }
+  // This is an outgoing connection, remove entry in pending link list
+  pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnConnectFail(hci::Address device, hci::ErrorCode reason) {
+  // Notify all pending links for this device
+  auto pending_link = pending_links_.find(device);
+  if (pending_link == pending_links_.end()) {
+    // There is no pending link, exit
+    LOG_DEBUG("Connection to %s failed without a pending link", device.ToString().c_str());
+    if (pending_dynamic_channels_callbacks_.find(device) != pending_dynamic_channels_callbacks_.end()) {
+      for (Link::PendingDynamicChannelConnection& callbacks : pending_dynamic_channels_callbacks_[device]) {
+        callbacks.handler_->Post(common::BindOnce(std::move(callbacks.on_fail_callback_),
+                                                  DynamicChannelManager::ConnectionResult{
+                                                      .hci_error = hci::ErrorCode::CONNECTION_TIMEOUT,
+                                                  }));
+      }
+      pending_dynamic_channels_.erase(device);
+      pending_dynamic_channels_callbacks_.erase(device);
+    }
+    return;
+  }
+  for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
+    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+        std::move(pending_fixed_channel_connection.on_fail_callback_),
+        FixedChannelManager::ConnectionResult{
+            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
+  }
+  // Remove entry in pending link list
+  pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnDisconnect(hci::Address device, hci::ErrorCode status) {
+  auto* link = GetLink(device);
+  ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database",
+             device.ToString().c_str(), static_cast<uint8_t>(status));
+  link->OnAclDisconnected(status);
+  links_.erase(device);
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager.h b/gd/l2cap/classic/internal/link_manager.h
new file mode 100644
index 0000000..6d282a2
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager.h
@@ -0,0 +1,95 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class LinkManager : public hci::ConnectionCallbacks {
+ public:
+  LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager,
+              FixedChannelServiceManagerImpl* fixed_channel_service_manager,
+              DynamicChannelServiceManagerImpl* dynamic_channel_service_manager,
+              l2cap::internal::ParameterProvider* parameter_provider)
+      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager),
+        fixed_channel_service_manager_(fixed_channel_service_manager),
+        dynamic_channel_service_manager_(dynamic_channel_service_manager), parameter_provider_(parameter_provider) {
+    acl_manager_->RegisterCallbacks(this, l2cap_handler_);
+  }
+
+  struct PendingFixedChannelConnection {
+    os::Handler* handler_;
+    FixedChannelManager::OnConnectionFailureCallback on_fail_callback_;
+  };
+
+  struct PendingLink {
+    std::vector<PendingFixedChannelConnection> pending_fixed_channel_connections_;
+  };
+
+  // ACL methods
+
+  Link* GetLink(hci::Address device);
+  void OnConnectSuccess(std::unique_ptr<hci::AclConnection> acl_connection) override;
+  void OnConnectFail(hci::Address device, hci::ErrorCode reason) override;
+  void OnDisconnect(hci::Address device, hci::ErrorCode status);
+
+  // FixedChannelManager methods
+
+  void ConnectFixedChannelServices(hci::Address device, PendingFixedChannelConnection pending_fixed_channel_connection);
+
+  // DynamicChannelManager methods
+
+  void ConnectDynamicChannelServices(hci::Address device,
+                                     Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm);
+
+ private:
+  // Dependencies
+  os::Handler* l2cap_handler_;
+  hci::AclManager* acl_manager_;
+  FixedChannelServiceManagerImpl* fixed_channel_service_manager_;
+  DynamicChannelServiceManagerImpl* dynamic_channel_service_manager_;
+  l2cap::internal::ParameterProvider* parameter_provider_;
+
+  // Internal states
+  std::unordered_map<hci::Address, PendingLink> pending_links_;
+  std::unordered_map<hci::Address, Link> links_;
+  std::unordered_map<hci::Address, std::list<Psm>> pending_dynamic_channels_;
+  std::unordered_map<hci::Address, std::list<Link::PendingDynamicChannelConnection>>
+      pending_dynamic_channels_callbacks_;
+  DISALLOW_COPY_AND_ASSIGN(LinkManager);
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager_test.cc b/gd/l2cap/classic/internal/link_manager_test.cc
new file mode 100644
index 0000000..aa7bfa4
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager_test.cc
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2018 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/classic/internal/link_manager.h"
+
+#include <future>
+#include <thread>
+
+#include "common/bind.h"
+#include "common/testing/bind_test_util.h"
+#include "dynamic_channel_service_manager_impl_mock.h"
+#include "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl_mock.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using hci::testing::MockAclManager;
+using l2cap::internal::testing::MockParameterProvider;
+using ::testing::_;  // Matcher to any value
+using ::testing::ByMove;
+using ::testing::DoAll;
+using testing::MockDynamicChannelServiceManagerImpl;
+using testing::MockFixedChannelServiceImpl;
+using testing::MockFixedChannelServiceManagerImpl;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+constexpr static auto kTestIdleDisconnectTimeoutLong = std::chrono::milliseconds(1000);
+constexpr static auto kTestIdleDisconnectTimeoutShort = std::chrono::milliseconds(30);
+
+class L2capClassicLinkManagerTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+    mock_parameter_provider_ = new MockParameterProvider;
+    EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+        .WillRepeatedly(Return(kTestIdleDisconnectTimeoutLong));
+  }
+
+  void TearDown() override {
+    delete mock_parameter_provider_;
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+  MockParameterProvider* mock_parameter_provider_ = nullptr;
+};
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl) {
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockDynamicChannelServiceManagerImpl mock_classic_dynamic_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   &mock_classic_dynamic_channel_service_manager, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+
+  std::unique_ptr<MockAclConnection> acl_connection = std::make_unique<MockAclConnection>();
+  EXPECT_CALL(*acl_connection, RegisterDisconnectCallback(_, l2cap_handler_)).Times(1);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+                                              common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+
+  // Step 4: Calling ConnectServices() to the same device will no trigger another connection attempt
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_2{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection_2));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code,
+            FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL);
+
+  // Step 5: Register new service will cause new channels to be created during ConnectServices()
+  MockFixedChannelServiceImpl mock_service_3;
+  results.emplace_back(kSmpBrCid + 1, &mock_service_3);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_3{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  std::unique_ptr<FixedChannel> channel_3;
+  EXPECT_CALL(mock_service_3, NotifyChannelCreation(_)).WillOnce([&channel_3](std::unique_ptr<FixedChannel> channel) {
+    channel_3 = std::move(channel);
+  });
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection_3));
+  EXPECT_NE(channel_3, nullptr);
+
+  user_handler->Clear();
+
+  classic_link_manager.OnDisconnect(device, hci::ErrorCode::SUCCESS);
+}
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_with_no_service) {
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   nullptr, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Make sure no service is registered
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without any service registered will result in failure
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(0);
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_with_hci_failure) {
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   nullptr, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection failure event should trigger connection failure callback
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).Times(0);
+  hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectFail,
+                                              common::Unretained(hci_connection_callbacks), device,
+                                              hci::ErrorCode::PAGE_TIMEOUT));
+  SyncHandler(hci_callback_handler);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR);
+  EXPECT_EQ(my_result.hci_error, hci::ErrorCode::PAGE_TIMEOUT);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, not_acquiring_channels_should_disconnect_acl_after_timeout) {
+  EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   nullptr, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+                                              common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  // Step 4: Leave channel IDLE long enough, they will disconnect
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+  // Step 5: Link disconnect will trigger all callbacks
+  classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, acquiring_channels_should_not_disconnect_acl_after_timeout) {
+  EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   nullptr, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+                                              common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  channel_1->Acquire();
+
+  // Step 4: Leave channel IDLE, it won't disconnect to due acquired channel 1
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+  // Step 5: Link disconnect will trigger all callbacks
+  classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, acquiring_and_releasing_channels_should_eventually_disconnect_acl) {
+  EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+                                   nullptr, mock_parameter_provider_);
+  EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+                                              common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  channel_1->Acquire();
+
+  // Step 4: Leave channel IDLE, it won't disconnect to due acquired channel 1
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+  // Step 5: Leave channel IDLE long enough, they will disconnect
+  channel_1->Release();
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+  // Step 6: Link disconnect will trigger all callbacks
+  classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_mock.h b/gd/l2cap/classic/internal/link_mock.h
new file mode 100644
index 0000000..3e0e2a6
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_mock.h
@@ -0,0 +1,56 @@
+/*
+ * 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 "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/scheduler_mock.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+using hci::testing::MockAclConnection;
+
+class MockLink : public Link {
+ public:
+  explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider)
+      : Link(handler, std::make_unique<MockAclConnection>(),
+             std::make_unique<l2cap::internal::testing::MockScheduler>(), parameter_provider, nullptr, nullptr){};
+  explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider,
+                    std::unique_ptr<hci::AclConnection> acl_connection,
+                    std::unique_ptr<l2cap::internal::Scheduler> scheduler)
+      : Link(handler, std::move(acl_connection), std::move(scheduler), parameter_provider, nullptr, nullptr){};
+  MOCK_METHOD(hci::Address, GetDevice, (), (override));
+  MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
+  MOCK_METHOD(void, Disconnect, (), (override));
+  MOCK_METHOD(std::shared_ptr<DynamicChannelImpl>, AllocateDynamicChannel,
+              (Psm psm, Cid cid, SecurityPolicy security_policy), (override));
+  MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
+  MOCK_METHOD(void, RefreshRefCount, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
new file mode 100644
index 0000000..7398c17
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -0,0 +1,656 @@
+/*
+ * 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/classic/internal/signalling_manager.h"
+
+#include <chrono>
+
+#include "common/bind.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+static constexpr auto kTimeout = std::chrono::seconds(3);
+
+ClassicSignallingManager::ClassicSignallingManager(os::Handler* handler, Link* link,
+                                                   DynamicChannelServiceManagerImpl* dynamic_service_manager,
+                                                   DynamicChannelAllocator* channel_allocator,
+                                                   FixedChannelServiceManagerImpl* fixed_service_manager)
+    : handler_(handler), link_(link), dynamic_service_manager_(dynamic_service_manager),
+      channel_allocator_(channel_allocator), fixed_service_manager_(fixed_service_manager), alarm_(handler) {
+  ASSERT(handler_ != nullptr);
+  ASSERT(link_ != nullptr);
+  signalling_channel_ = link_->AllocateFixedChannel(kClassicSignallingCid, {});
+  signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
+      handler_, common::Bind(&ClassicSignallingManager::on_incoming_packet, common::Unretained(this)));
+  enqueue_buffer_ =
+      std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
+}
+
+ClassicSignallingManager::~ClassicSignallingManager() {
+  enqueue_buffer_.reset();
+  signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
+  signalling_channel_ = nullptr;
+}
+
+void ClassicSignallingManager::OnCommandReject(CommandRejectView command_reject_view) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected command reject: no pending request");
+    return;
+  }
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+
+  SignalId signal_id = command_reject_view.GetIdentifier();
+  if (last_sent_command.signal_id_ != signal_id) {
+    LOG_WARN("Unknown command reject");
+    return;
+  }
+  handle_send_next_command();
+
+  LOG_INFO("Command rejected");
+}
+
+void ClassicSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid) {
+  PendingCommand pending_command = {next_signal_id_, CommandCode::CONNECTION_REQUEST, psm, local_cid, {}, {}, {}};
+  next_signal_id_++;
+  pending_commands_.push(std::move(pending_command));
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendConfigurationRequest(Cid remote_cid,
+                                                        std::vector<std::unique_ptr<ConfigurationOption>> config) {
+  PendingCommand pending_command = {next_signal_id_,  CommandCode::CONFIGURATION_REQUEST, {}, {}, remote_cid, {},
+                                    std::move(config)};
+  next_signal_id_++;
+  pending_commands_.push(std::move(pending_command));
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+  PendingCommand pending_command = {
+      next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
+  next_signal_id_++;
+  pending_commands_.push(std::move(pending_command));
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType type) {
+  PendingCommand pending_command = {next_signal_id_, CommandCode::INFORMATION_REQUEST, {}, {}, {}, type, {}};
+  next_signal_id_++;
+  pending_commands_.push(std::move(pending_command));
+  if (pending_commands_.size() == 1) {
+    handle_send_next_command();
+  }
+}
+
+void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload) {
+  LOG_WARN("Not supported");
+}
+
+void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) {
+  if (!IsPsmValid(psm)) {
+    LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  if (remote_cid == kInvalidCid) {
+    LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::INVALID_CID,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+  if (channel_allocator_->IsPsmUsed(psm)) {
+    LOG_WARN("Psm already exists");
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
+    LOG_INFO("Service for this psm (%d) is not registered", psm);
+    send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+                             ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+    return;
+  }
+
+  auto new_channel = link_->AllocateDynamicChannel(psm, remote_cid, {});
+  if (new_channel == nullptr) {
+    LOG_WARN("Can't allocate dynamic channel");
+    return;
+  }
+  send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
+                           ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+  auto* service = dynamic_service_manager_->GetService(psm);
+  auto initial_config = service->GetConfigOption();
+  if (!link_->GetRemoteSupportsErtm()) {
+    initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+  }
+  auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
+  mtu_configuration->mtu_ = initial_config.incoming_mtu;
+  auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
+  fcs_option->fcs_type_ = FcsType::NO_FCS;
+  auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+  switch (initial_config.channel_mode) {
+    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
+      retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+      break;
+    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
+      retransmission_flow_control_configuration->mode_ =
+          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+      // TODO: Decide where to put initial values
+      retransmission_flow_control_configuration->tx_window_size_ = 10;
+      retransmission_flow_control_configuration->max_transmit_ = 20;
+      retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
+      retransmission_flow_control_configuration->monitor_time_out_ = 12000;
+      retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
+      break;
+  }
+
+  new_channel->SetRetransmissionFlowControlConfig(*retransmission_flow_control_configuration);
+  new_channel->SetIncomingMtu(initial_config.incoming_mtu);
+  std::vector<std::unique_ptr<ConfigurationOption>> config;
+  config.emplace_back(std::move(mtu_configuration));
+  config.emplace_back(std::move(retransmission_flow_control_configuration));
+  config.emplace_back(std::move(fcs_option));
+  SendConfigurationRequest(remote_cid, std::move(config));
+}
+
+void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid,
+                                                    ConnectionResponseResult result, ConnectionResponseStatus status) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected response: no pending request");
+    return;
+  }
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+  if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::CONNECTION_REQUEST) {
+    LOG_WARN("Received unexpected connection response");
+    return;
+  }
+  if (last_sent_command.source_cid_ != cid) {
+    LOG_WARN("SCID doesn't match: expected %d, received %d", last_sent_command.source_cid_, cid);
+    handle_send_next_command();
+    return;
+  }
+  if (result != ConnectionResponseResult::SUCCESS) {
+    handle_send_next_command();
+    return;
+  }
+  Psm pending_psm = last_sent_command.psm_;
+  auto new_channel = link_->AllocateReservedDynamicChannel(cid, pending_psm, remote_cid, {});
+  if (new_channel == nullptr) {
+    LOG_WARN("Can't allocate dynamic channel");
+    handle_send_next_command();
+    return;
+  }
+  alarm_.Cancel();
+  auto initial_config = link_->GetConfigurationForInitialConfiguration(new_channel->GetCid());
+  if (!link_->GetRemoteSupportsErtm()) {
+    initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+  }
+  auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
+  mtu_configuration->mtu_ = initial_config.incoming_mtu;
+  auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+  switch (initial_config.channel_mode) {
+    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
+      retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+      break;
+    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
+      retransmission_flow_control_configuration->mode_ =
+          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+      // TODO: Decide where to put initial values
+      retransmission_flow_control_configuration->tx_window_size_ = 10;
+      retransmission_flow_control_configuration->max_transmit_ = 20;
+      retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
+      retransmission_flow_control_configuration->monitor_time_out_ = 12000;
+      retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
+      break;
+  }
+  std::vector<std::unique_ptr<ConfigurationOption>> config;
+  config.emplace_back(std::move(mtu_configuration));
+  if (initial_config.channel_mode != DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC) {
+    config.emplace_back(std::move(retransmission_flow_control_configuration));
+  }
+  SendConfigurationRequest(remote_cid, {});
+}
+
+void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+                                                      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->SetRetransmissionFlowControlConfig(*config);
+        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_);
+  channel->SetIncomingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
+  if (channel->GetOutgoingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+    std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
+    if (channel->local_initiated_) {
+      link_->NotifyChannelCreation(cid, std::move(user_channel));
+    } else {
+      dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
+    }
+  }
+}
+
+void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+                                                       ConfigurationResponseResult result,
+                                                       std::vector<std::unique_ptr<ConfigurationOption>> options) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected response: no pending request");
+    return;
+  }
+
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+
+  auto channel = channel_allocator_->FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_WARN("Configuration request for an unknown channel");
+    handle_send_next_command();
+    return;
+  }
+
+  channel->SetOutgoingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
+  if (channel->GetIncomingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+    std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
+    if (channel->local_initiated_) {
+      link_->NotifyChannelCreation(cid, std::move(user_channel));
+    } else {
+      dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
+    }
+  }
+  alarm_.Cancel();
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
+  // TODO: check cid match
+  auto channel = channel_allocator_->FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_WARN("Disconnect request for an unknown channel");
+    return;
+  }
+  auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+  channel->OnClosed(hci::ErrorCode::SUCCESS);
+  link_->FreeDynamicChannel(cid);
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected response: no pending request");
+    return;
+  }
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+  alarm_.Cancel();
+
+  if (last_sent_command.signal_id_ != signal_id ||
+      last_sent_command.command_code_ != CommandCode::DISCONNECTION_REQUEST) {
+    return;
+  }
+
+  auto channel = channel_allocator_->FindChannelByCid(cid);
+  if (channel == nullptr) {
+    LOG_WARN("Disconnect response for an unknown channel");
+    handle_send_next_command();
+    return;
+  }
+
+  channel->OnClosed(hci::ErrorCode::SUCCESS);
+  link_->FreeDynamicChannel(cid);
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+  std::vector<uint8_t> packet_vector{packet.begin(), packet.end()};
+  auto raw_builder = std::make_unique<packet::RawBuilder>();
+  raw_builder->AddOctets(packet_vector);
+  auto builder = EchoResponseBuilder::Create(signal_id.Value(), std::move(raw_builder));
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected response: no pending request");
+    return;
+  }
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+
+  if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::ECHO_REQUEST) {
+    return;
+  }
+  LOG_INFO("Echo response received");
+  alarm_.Cancel();
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnInformationRequest(SignalId signal_id, InformationRequestInfoType type) {
+  switch (type) {
+    case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+      auto response = InformationResponseConnectionlessMtuBuilder::Create(
+          signal_id.Value(), InformationRequestResult::SUCCESS, kDefaultClassicMtu);
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      break;
+    }
+    case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+      // TODO: implement this response
+      auto response = InformationResponseExtendedFeaturesBuilder::Create(
+          signal_id.Value(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      break;
+    }
+    case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+      auto response = InformationResponseFixedChannelsBuilder::Create(
+          signal_id.Value(), InformationRequestResult::SUCCESS, fixed_service_manager_->GetSupportedFixedChannelMask());
+      enqueue_buffer_->Enqueue(std::move(response), handler_);
+      break;
+    }
+  }
+}
+
+void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& response) {
+  if (pending_commands_.empty()) {
+    LOG_WARN("Unexpected response: no pending request");
+    return;
+  }
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+
+  if (last_sent_command.signal_id_ != signal_id ||
+      last_sent_command.command_code_ != CommandCode::INFORMATION_REQUEST) {
+    return;
+  }
+
+  auto type = response.GetInfoType();
+  switch (type) {
+    case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+      auto view = InformationResponseConnectionlessMtuView::Create(response);
+      if (!view.IsValid()) {
+        LOG_WARN("Invalid InformationResponseConnectionlessMtu received");
+        return;
+      }
+      link_->SetRemoteConnectionlessMtu(view.GetConnectionlessMtu());
+      break;
+    }
+    case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+      auto view = InformationResponseExtendedFeaturesView::Create(response);
+      if (!view.IsValid()) {
+        LOG_WARN("Invalid InformationResponseExtendedFeatures received");
+        return;
+      }
+      link_->SetRemoteSupportsErtm((view.GetEnhancedRetransmissionMode()));
+      link_->SetRemoteSupportsFcs(view.GetFcsOption());
+      // We don't care about other parameters
+      break;
+    }
+    case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+      auto view = InformationResponseFixedChannelsView::Create(response);
+      if (!view.IsValid()) {
+        LOG_WARN("Invalid InformationResponseFixedChannel received");
+        return;
+      }
+      // We don't use fixed channels (connectionless or BR/EDR security) for now so we don't care
+      break;
+    }
+  }
+
+  alarm_.Cancel();
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::on_incoming_packet() {
+  auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
+  ControlView control_packet_view = ControlView::Create(*packet);
+  if (!control_packet_view.IsValid()) {
+    LOG_WARN("Invalid signalling packet received");
+    return;
+  }
+  auto code = control_packet_view.GetCode();
+  switch (code) {
+    case CommandCode::COMMAND_REJECT: {
+      CommandRejectView command_reject_view = CommandRejectView::Create(control_packet_view);
+      if (!command_reject_view.IsValid()) {
+        return;
+      }
+      OnCommandReject(command_reject_view);
+      return;
+    }
+    case CommandCode::CONNECTION_REQUEST: {
+      ConnectionRequestView connection_request_view = ConnectionRequestView::Create(control_packet_view);
+      if (!connection_request_view.IsValid()) {
+        return;
+      }
+      OnConnectionRequest(control_packet_view.GetIdentifier(), connection_request_view.GetPsm(),
+                          connection_request_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::CONNECTION_RESPONSE: {
+      ConnectionResponseView connection_response_view = ConnectionResponseView::Create(control_packet_view);
+      if (!connection_response_view.IsValid()) {
+        return;
+      }
+      OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
+                           connection_response_view.GetSourceCid(), connection_response_view.GetResult(),
+                           connection_response_view.GetStatus());
+      return;
+    }
+    case CommandCode::CONFIGURATION_REQUEST: {
+      ConfigurationRequestView configuration_request_view = ConfigurationRequestView::Create(control_packet_view);
+      if (!configuration_request_view.IsValid()) {
+        return;
+      }
+      OnConfigurationRequest(configuration_request_view.GetIdentifier(), configuration_request_view.GetDestinationCid(),
+                             configuration_request_view.GetContinuation(), configuration_request_view.GetConfig());
+      return;
+    }
+    case CommandCode::CONFIGURATION_RESPONSE: {
+      ConfigurationResponseView configuration_response_view = ConfigurationResponseView::Create(control_packet_view);
+      if (!configuration_response_view.IsValid()) {
+        return;
+      }
+      OnConfigurationResponse(configuration_response_view.GetIdentifier(), configuration_response_view.GetSourceCid(),
+                              configuration_response_view.GetContinuation(), configuration_response_view.GetResult(),
+                              configuration_response_view.GetConfig());
+      return;
+    }
+    case CommandCode::DISCONNECTION_REQUEST: {
+      DisconnectionRequestView disconnection_request_view = DisconnectionRequestView::Create(control_packet_view);
+      if (!disconnection_request_view.IsValid()) {
+        return;
+      }
+      OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
+                             disconnection_request_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::DISCONNECTION_RESPONSE: {
+      DisconnectionResponseView disconnection_response_view = DisconnectionResponseView::Create(control_packet_view);
+      if (!disconnection_response_view.IsValid()) {
+        return;
+      }
+      OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
+                              disconnection_response_view.GetDestinationCid(),
+                              disconnection_response_view.GetSourceCid());
+      return;
+    }
+    case CommandCode::ECHO_REQUEST: {
+      EchoRequestView echo_request_view = EchoRequestView::Create(control_packet_view);
+      if (!echo_request_view.IsValid()) {
+        return;
+      }
+      OnEchoRequest(echo_request_view.GetIdentifier(), echo_request_view.GetPayload());
+      return;
+    }
+    case CommandCode::ECHO_RESPONSE: {
+      EchoResponseView echo_response_view = EchoResponseView::Create(control_packet_view);
+      if (!echo_response_view.IsValid()) {
+        return;
+      }
+      OnEchoResponse(echo_response_view.GetIdentifier(), echo_response_view.GetPayload());
+      return;
+    }
+    case CommandCode::INFORMATION_REQUEST: {
+      InformationRequestView information_request_view = InformationRequestView::Create(control_packet_view);
+      if (!information_request_view.IsValid()) {
+        return;
+      }
+      OnInformationRequest(information_request_view.GetIdentifier(), information_request_view.GetInfoType());
+      return;
+    }
+    case CommandCode::INFORMATION_RESPONSE: {
+      InformationResponseView information_response_view = InformationResponseView::Create(control_packet_view);
+      if (!information_response_view.IsValid()) {
+        return;
+      }
+      OnInformationResponse(information_response_view.GetIdentifier(), information_response_view);
+      return;
+    }
+    default:
+      LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
+      auto builder = CommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier());
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      return;
+  }
+}
+
+void ClassicSignallingManager::send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid,
+                                                        ConnectionResponseResult result,
+                                                        ConnectionResponseStatus status) {
+  auto builder = ConnectionResponseBuilder::Create(signal_id.Value(), local_cid, remote_cid, result, status);
+  enqueue_buffer_->Enqueue(std::move(builder), handler_);
+}
+
+void ClassicSignallingManager::on_command_timeout() {
+  LOG_WARN("Response time out");
+  if (pending_commands_.empty()) {
+    LOG_ERROR("No pending command");
+    return;
+  }
+
+  auto last_sent_command = std::move(pending_commands_.front());
+  pending_commands_.pop();
+  switch (last_sent_command.command_code_) {
+    case CommandCode::CONFIGURATION_REQUEST: {
+      SendDisconnectionRequest(last_sent_command.source_cid_, last_sent_command.destination_cid_);
+      break;
+    }
+    default:
+      break;
+  }
+  handle_send_next_command();
+}
+
+void ClassicSignallingManager::handle_send_next_command() {
+  if (pending_commands_.empty()) {
+    return;
+  }
+  auto& last_sent_command = pending_commands_.front();
+
+  auto signal_id = last_sent_command.signal_id_;
+  auto psm = last_sent_command.psm_;
+  auto source_cid = last_sent_command.source_cid_;
+  auto destination_cid = last_sent_command.destination_cid_;
+  auto info_type = last_sent_command.info_type_;
+  auto config = std::move(last_sent_command.config_);
+  switch (last_sent_command.command_code_) {
+    case CommandCode::CONNECTION_REQUEST: {
+      auto builder = ConnectionRequestBuilder::Create(signal_id.Value(), psm, source_cid);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    case CommandCode::CONFIGURATION_REQUEST: {
+      auto builder =
+          ConfigurationRequestBuilder::Create(signal_id.Value(), destination_cid, Continuation::END, std::move(config));
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    case CommandCode::DISCONNECTION_REQUEST: {
+      auto builder = DisconnectionRequestBuilder::Create(signal_id.Value(), destination_cid, source_cid);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    case CommandCode::INFORMATION_REQUEST: {
+      auto builder = InformationRequestBuilder::Create(signal_id.Value(), info_type);
+      enqueue_buffer_->Enqueue(std::move(builder), handler_);
+      alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+                      kTimeout);
+      break;
+    }
+    default:
+      LOG_WARN("Unsupported command code 0x%x", static_cast<int>(last_sent_command.command_code_));
+  }
+}
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager.h b/gd/l2cap/classic/internal/signalling_manager.h
new file mode 100644
index 0000000..0e17ec7
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager.h
@@ -0,0 +1,120 @@
+/*
+ * 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 <cstdint>
+#include <queue>
+#include <vector>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/psm.h"
+#include "l2cap/signal_id.h"
+#include "os/alarm.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+struct PendingCommand {
+  SignalId signal_id_;
+  CommandCode command_code_;
+  Psm psm_;
+  Cid source_cid_;
+  Cid destination_cid_;
+  InformationRequestInfoType info_type_;
+  std::vector<std::unique_ptr<ConfigurationOption>> config_;
+};
+
+class Link;
+
+class ClassicSignallingManager {
+ public:
+  ClassicSignallingManager(os::Handler* handler, Link* link,
+                           classic::internal::DynamicChannelServiceManagerImpl* dynamic_service_manager,
+                           classic::internal::DynamicChannelAllocator* channel_allocator,
+                           classic::internal::FixedChannelServiceManagerImpl* fixed_service_manager);
+
+  virtual ~ClassicSignallingManager();
+
+  void OnCommandReject(CommandRejectView command_reject_view);
+
+  void SendConnectionRequest(Psm psm, Cid local_cid);
+
+  void SendConfigurationRequest(Cid remote_cid, std::vector<std::unique_ptr<ConfigurationOption>> config);
+
+  void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+
+  void SendInformationRequest(InformationRequestInfoType type);
+
+  void SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload);
+
+  void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid);
+
+  void OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid, ConnectionResponseResult result,
+                            ConnectionResponseStatus status);
+
+  void OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid);
+
+  void OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid);
+
+  void OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+                              std::vector<std::unique_ptr<ConfigurationOption>>);
+
+  void OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+                               ConfigurationResponseResult result, std::vector<std::unique_ptr<ConfigurationOption>>);
+
+  void OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+  void OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+  void OnInformationRequest(SignalId signal_id, InformationRequestInfoType type);
+
+  void OnInformationResponse(SignalId signal_id, const InformationResponseView& response);
+
+ private:
+  void on_incoming_packet();
+  void send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid, ConnectionResponseResult result,
+                                ConnectionResponseStatus status);
+  void on_command_timeout();
+  void handle_send_next_command();
+
+  os::Handler* handler_;
+  Link* link_;
+  std::shared_ptr<classic::internal::FixedChannelImpl> signalling_channel_;
+  DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+  DynamicChannelAllocator* channel_allocator_;
+  FixedChannelServiceManagerImpl* fixed_service_manager_;
+  std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> enqueue_buffer_;
+  PendingCommand last_sent_command_;
+  std::queue<PendingCommand> pending_commands_;
+  os::Alarm alarm_;
+  SignalId next_signal_id_ = kInitialSignalId;
+};
+
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager_test.cc b/gd/l2cap/classic/internal/signalling_manager_test.cc
new file mode 100644
index 0000000..a89b445
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager_test.cc
@@ -0,0 +1,67 @@
+/*
+ * 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/classic/internal/signalling_manager.h"
+
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace {
+
+class L2capClassicSignallingManagerTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicSignallingManagerTest, precondition) {}
+
+}  // namespace
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module.cc b/gd/l2cap/classic/l2cap_classic_module.cc
new file mode 100644
index 0000000..bc30c86
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module.cc
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "l2cap2"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link_manager.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/classic/l2cap_classic_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+const ModuleFactory L2capClassicModule::Factory = ModuleFactory([]() { return new L2capClassicModule(); });
+
+struct L2capClassicModule::impl {
+  impl(os::Handler* l2cap_handler, hci::AclManager* acl_manager)
+      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager) {}
+  os::Handler* l2cap_handler_;
+  hci::AclManager* acl_manager_;
+  l2cap::internal::ParameterProvider parameter_provider_;
+  internal::FixedChannelServiceManagerImpl fixed_channel_service_manager_impl_{l2cap_handler_};
+  internal::DynamicChannelServiceManagerImpl dynamic_channel_service_manager_impl_{l2cap_handler_};
+  internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
+                                      &dynamic_channel_service_manager_impl_, &parameter_provider_};
+};
+
+void L2capClassicModule::ListDependencies(ModuleList* list) {
+  list->add<hci::AclManager>();
+}
+
+void L2capClassicModule::Start() {
+  pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::AclManager>());
+}
+
+void L2capClassicModule::Stop() {
+  pimpl_.reset();
+}
+
+std::string L2capClassicModule::ToString() const {
+  return "L2cap Classic Module";
+}
+
+std::unique_ptr<FixedChannelManager> L2capClassicModule::GetFixedChannelManager() {
+  return std::unique_ptr<FixedChannelManager>(new FixedChannelManager(&pimpl_->fixed_channel_service_manager_impl_,
+                                                                      &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+std::unique_ptr<DynamicChannelManager> L2capClassicModule::GetDynamicChannelManager() {
+  return std::unique_ptr<DynamicChannelManager>(new DynamicChannelManager(
+      &pimpl_->dynamic_channel_service_manager_impl_, &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/l2cap_classic_module.h b/gd/l2cap/classic/l2cap_classic_module.h
new file mode 100644
index 0000000..7255bc3
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module.h
@@ -0,0 +1,62 @@
+/*
+ * 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 <memory>
+
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule : public bluetooth::Module {
+ public:
+  L2capClassicModule() = default;
+  ~L2capClassicModule() = default;
+
+  /**
+   * Get the api to the classic fixed channel l2cap module
+   */
+  std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
+
+  /**
+   * Get the api to the classic dynamic channel l2cap module
+   */
+  std::unique_ptr<DynamicChannelManager> GetDynamicChannelManager();
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+
+  void Start() override;
+
+  void Stop() override;
+
+  std::string ToString() const override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(L2capClassicModule);
+};
+
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel.cc b/gd/l2cap/classic_fixed_channel.cc
deleted file mode 100644
index 6c08eec..0000000
--- a/gd/l2cap/classic_fixed_channel.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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/classic_fixed_channel.h"
-
-namespace bluetooth {
-namespace l2cap {
-void ClassicFixedChannel::RegisterOnCloseCallback(os::Handler* handler, OnCloseCallback callback) {}
-void ClassicFixedChannel::Acquire() {}
-void ClassicFixedChannel::Release() {}
-common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*
-ClassicFixedChannel::GetQueueUpEnd() const {
-  return nullptr;
-}
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel.h b/gd/l2cap/classic_fixed_channel.h
deleted file mode 100644
index 1cc6117..0000000
--- a/gd/l2cap/classic_fixed_channel.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 "common/bidi_queue.h"
-#include "common/callback.h"
-#include "os/handler.h"
-#include "packet/base_packet_builder.h"
-#include "packet/packet_view.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-/**
- * L2CAP fixed channel object. When a new object is created, it must be
- * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
- * Otherwise, {@link FixeChannel#Release()} will be called automatically.
- *
- */
-class ClassicFixedChannel {
- public:
-  using OnCloseCallback = common::Callback<void()>;
-
-  /**
-   * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
-   * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
-   * resource will be freed immediately after closing.
-   *
-   * @param on_close The callback invoked upon channel closing.
-   */
-  void RegisterOnCloseCallback(os::Handler* handler, OnCloseCallback on_close);
-
-  /**
-   * Indicate that this Fixed Channel is being used. This will prevent ACL
-   * connection from being disconnected.
-   */
-  void Acquire();
-
-  /**
-   * Indicate that this Fixed Channel is no longer being used. ACL connection
-   * will be disconnected after X seconds if no other DynamicChannel is connected
-   * or no other Fixed Channel is using this ACL connection. However a module can
-   * still receive data on this channel as long as it remains open.
-   */
-  void Release();
-
-  /**
-   * This method will retrieve the data channel queue to send and receive packets.
-   *
-   * {@see BidiQueueEnd}
-   *
-   * @return The upper end of a bi-directional queue.
-   */
-  common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueUpEnd() const;
-};
-
-}  // namespace l2cap
-}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_manager.cc b/gd/l2cap/classic_fixed_channel_manager.cc
deleted file mode 100644
index 928bedb..0000000
--- a/gd/l2cap/classic_fixed_channel_manager.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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/classic_fixed_channel_manager.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-bool ClassicFixedChannelManager::ConnectServices(common::Address device,
-                                                 OnConnectionFailureCallback on_connection_failure,
-                                                 os::Handler* handler) {
-  return false;
-}
-
-bool ClassicFixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
-                                                 OnRegistrationCompleteCallback on_registration_complete,
-                                                 OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
-  return true;
-}
-
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel_manager.h b/gd/l2cap/classic_fixed_channel_manager.h
deleted file mode 100644
index cacc368..0000000
--- a/gd/l2cap/classic_fixed_channel_manager.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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 "common/address.h"
-#include "l2cap/cid.h"
-#include "l2cap/classic_fixed_channel.h"
-#include "l2cap/classic_fixed_channel_service.h"
-#include "l2cap/security_policy.h"
-#include "os/handler.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-class ClassicFixedChannelManager {
-  /**
-   * OnConnectionFailureCallback(std::string failure_reason);
-   */
-  using OnConnectionFailureCallback = common::OnceCallback<void(std::string)>;
-
-  /**
-   * OnConnectionOpenCallback(ClassicFixedChannel channel);
-   */
-  using OnConnectionOpenCallback = common::OnceCallback<void(ClassicFixedChannel)>;
-
-  enum RegistrationResult { SUCCESS, FAIL };
-
-  /**
-   * OnRegistrationFailureCallback(RegistrationResult result, ClassicFixedChannelService service);
-   */
-  using OnRegistrationCompleteCallback = common::OnceCallback<void(RegistrationResult, ClassicFixedChannelService)>;
-
-  /**
-   * Connect to ALL fixed channels on a remote device
-   *
-   * - This method is asynchronous
-   * - When false is returned, the connection fails immediately
-   * - When true is returned, method caller should wait for on_fail_callback or on_open_callback registered through
-   *   RegisterService() API.
-   * - If an ACL connection does not exist, this method will create an ACL connection. As a result, on_open_callback
-   *   supplied through RegisterService() will be triggered to provide the actual ClassicFixedChannel objects
-   * - If fixed channel on a remote device is already reported as connected via on_open_callback and has been acquired
-   *   via ClassicFixedChannel#Acquire() API, it won't be reported again
-   * - If no service is registered, this call is a no-op and on on_fail_callback will be triggered
-   *
-   * NOTE:
-   * This call will initiate an effort to connect all fixed channel services on a remote device.
-   * Due to the connectionless nature of fixed channels, all fixed channels will be connected together.
-   * If a fixed channel service does not need a particular fixed channel. It should release the received
-   * channel immediately after receiving on_open_callback via ClassicFixedChannel#Release()
-   *
-   * A module calling ConnectServices() must have called RegisterService() before.
-   * The callback will come back from on_open_callback in the service that is registered
-   *
-   * @param device: Remote device to make this connection.
-   * @param on_fail_callback: A callback to indicate connection failure along with a status code.
-   * @param handler: The handler context in which to execute the @callback parameters.
-   *
-   * Returns: true if connection was able to be initiated, false otherwise.
-   */
-  bool ConnectServices(common::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler);
-
-  /**
-   * Register a service to receive incoming connections bound to a specific channel.
-   *
-   * - This method is asynchronous.
-   * - When false is returned, the registration fails immediately.
-   * - When true is returned, method caller should wait for on_service_registered callback that contains a
-   *   ClassicFixedChannelService object. The registered service can be managed from that object.
-   * - If a CID is already registered or some other error happens,
-   * - After a service is registered, any classic ACL connection will create a ClassicFixedChannel object that is
-   *   delivered through on_open_callback
-   * - on_open_callback, if any, must be triggered after on_service_registered callback
-   *
-   * @param cid: Classic cid used to receive incoming connections
-   * @param security_policy: The security policy used for the connection.
-   * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
-   *        not SUCCESS, it means service is not registered due to reasons like CID already take
-   * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
-   * @param handler: The handler context in which to execute the @callback parameter.
-   */
-  bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
-                       OnRegistrationCompleteCallback on_registration_complete,
-                       OnConnectionOpenCallback on_connection_open, os::Handler* handler);
-};
-
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic_fixed_channel_service.h b/gd/l2cap/classic_fixed_channel_service.h
deleted file mode 100644
index 9fddeb6..0000000
--- a/gd/l2cap/classic_fixed_channel_service.h
+++ /dev/null
@@ -1,39 +0,0 @@
-
-/*
- * 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 "common/address.h"
-#include "common/callback.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-class ClassicFixedChannelService {
- public:
-  using OnUnregisteredCallback = common::OnceCallback<void()>;
-
-  /**
-   * Unregister a service from L2CAP module. This operation cannot fail.
-   * All channels opened for this service will be invalidated.
-   *
-   * @param on_unregistered will be triggered when unregistration is complete
-   */
-  void Unregister(OnUnregisteredCallback on_unregistered);
-};
-
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/constant.h b/gd/l2cap/constant.h
deleted file mode 100644
index 51b07c5..0000000
--- a/gd/l2cap/constant.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 <chrono>
-#include <cstddef>
-
-#include "l2cap/cid.h"
-#include "l2cap/signal_id.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-constexpr size_t kChannelQueueCapacity = 10;
-constexpr size_t kLinkQueueCapacity = 10;
-constexpr std::chrono::milliseconds bogus_link_wakeup_time = std::chrono::milliseconds(15000);
-
-constexpr SignalId kInitialSignalId = SignalId(0x80);
-
-// Time after last channels closes before link is torn down
-constexpr auto kLinkDisconnectTimeout = std::chrono::seconds(30);
-
-// TODO(cmanton) Random numbers for now
-constexpr auto kChannelConnectionTimeout = std::chrono::seconds(30);
-constexpr auto kChannelConnectionPendingTimeout = std::chrono::seconds(30);
-constexpr auto kChannelConfigurationTimeout = std::chrono::seconds(30);
-constexpr auto kChannelDisconnectionTimeout = std::chrono::seconds(30);
-
-// The depth of buffering that the signalling channel can handle.
-constexpr auto kSignallingChannelSize = 20;
-
-}  // namespace l2cap
-}  // namespace bluetooth
diff --git a/gd/l2cap/facade.cc b/gd/l2cap/facade.cc
deleted file mode 100644
index 50b2d60..0000000
--- a/gd/l2cap/facade.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 <cstdint>
-#include <unordered_map>
-
-#include "common/address.h"
-#include "common/bind.h"
-#include "grpc/grpc_event_stream.h"
-#include "l2cap/facade.grpc.pb.h"
-#include "l2cap/facade.h"
-#include "l2cap/l2cap_layer.h"
-#include "l2cap/l2cap_packets.h"
-#include "os/log.h"
-#include "packet/raw_builder.h"
-
-using ::grpc::ServerAsyncResponseWriter;
-using ::grpc::ServerAsyncWriter;
-using ::grpc::ServerContext;
-
-using ::bluetooth::facade::EventStreamRequest;
-using ::bluetooth::packet::RawBuilder;
-
-namespace bluetooth {
-namespace l2cap {
-
-class L2capModuleFacadeService : public L2capModuleFacade::Service {
- public:
-  L2capModuleFacadeService(l2cap::L2capLayer* l2cap_layer, ::bluetooth::os::Handler* facade_handler)
-      : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler) {
-    ASSERT(l2cap_layer_ != nullptr);
-    ASSERT(facade_handler_ != nullptr);
-  }
-
-  ::grpc::Status NoOp(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-                      ::google::protobuf::Empty* response) override {
-    return ::grpc::Status::OK;
-  }
-
- private:
-  l2cap::L2capLayer* l2cap_layer_;
-  ::bluetooth::os::Handler* facade_handler_;
-  std::mutex mutex_;
-};
-
-void L2capModuleFacadeModule::ListDependencies(ModuleList* list) {
-  ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
-  list->add<l2cap::L2capLayer>();
-}
-
-void L2capModuleFacadeModule::Start() {
-  ::bluetooth::grpc::GrpcFacadeModule::Start();
-  service_ = new L2capModuleFacadeService(GetDependency<l2cap::L2capLayer>(), GetHandler());
-}
-
-void L2capModuleFacadeModule::Stop() {
-  delete service_;
-  ::bluetooth::grpc::GrpcFacadeModule::Stop();
-}
-
-::grpc::Service* L2capModuleFacadeModule::GetService() const {
-  return service_;
-}
-
-const ModuleFactory L2capModuleFacadeModule::Factory =
-    ::bluetooth::ModuleFactory([]() { return new L2capModuleFacadeModule(); });
-
-}  // namespace l2cap
-}  // namespace bluetooth
diff --git a/gd/l2cap/facade.proto b/gd/l2cap/facade.proto
deleted file mode 100644
index a5abec6..0000000
--- a/gd/l2cap/facade.proto
+++ /dev/null
@@ -1,10 +0,0 @@
-syntax = "proto3";
-
-package bluetooth.l2cap;
-
-import "google/protobuf/empty.proto";
-import "facade/common.proto";
-
-service L2capModuleFacade {
-  rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty) {}
-}
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller.cc b/gd/l2cap/internal/basic_mode_channel_data_controller.cc
new file mode 100644
index 0000000..1a049aa
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller.cc
@@ -0,0 +1,46 @@
+/*
+ * 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/basic_mode_channel_data_controller.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+BasicModeDataController::BasicModeDataController(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 BasicModeDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
+  auto l2cap_information = BasicFrameBuilder::Create(remote_cid_, std::move(sdu));
+  pdu_queue_.emplace(std::move(l2cap_information));
+  scheduler_->OnPacketsReady(cid_, 1);
+}
+
+void BasicModeDataController::OnPdu(BasicFrameView pdu) {
+  enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(pdu.GetPayload()), handler_);
+}
+
+std::unique_ptr<BasicFrameBuilder> BasicModeDataController::GetNextPacket() {
+  auto next = std::move(pdu_queue_.front());
+  pdu_queue_.pop();
+  return next;
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller.h b/gd/l2cap/internal/basic_mode_channel_data_controller.h
new file mode 100644
index 0000000..41d03fa
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.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 BasicModeDataController : public DataController {
+ public:
+  using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+  using UpperDequeue = packet::BasePacketBuilder;
+  using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+  BasicModeDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+                          Scheduler* scheduler);
+
+  void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
+
+  void OnPdu(BasicFrameView pdu) override;
+
+  std::unique_ptr<BasicFrameBuilder> GetNextPacket() override;
+
+  void EnableFcs(bool enabled) override {}
+  void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {}
+
+ private:
+  Cid cid_;
+  Cid remote_cid_;
+  os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+  os::Handler* handler_;
+  std::queue<std::unique_ptr<BasicFrameBuilder>> pdu_queue_;
+  Scheduler* scheduler_;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc b/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc
new file mode 100644
index 0000000..35c3002
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc
@@ -0,0 +1,98 @@
+/*
+ * 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/basic_mode_channel_data_controller.h"
+
+#include <gtest/gtest.h>
+
+#include "l2cap/internal/scheduler_mock.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;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+  auto status = future.wait_for(std::chrono::milliseconds(300));
+  EXPECT_EQ(status, std::future_status::ready);
+}
+
+class BasicModeDataControllerTest : public ::testing::Test {
+ 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_);
+  }
+
+  void TearDown() override {
+    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;
+};
+
+TEST_F(BasicModeDataControllerTest, transmit) {
+  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+  testing::MockScheduler scheduler;
+  BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+  EXPECT_CALL(scheduler, OnPacketsReady(1, 1));
+  controller.OnSdu(CreateSdu({1, 2, 3}));
+  auto next_packet = controller.GetNextPacket();
+  EXPECT_NE(next_packet, nullptr);
+}
+
+TEST_F(BasicModeDataControllerTest, receive) {
+  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+  testing::MockScheduler scheduler;
+  BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+  auto base_view = GetPacketView(CreateSdu({0, 0, 1, 0}));
+  auto basic_frame_view = BasicFrameView::Create(base_view);
+  EXPECT_TRUE(basic_frame_view.IsValid());
+  controller.OnPdu(basic_frame_view);
+  sync_handler(queue_handler_);
+  auto packet_view = channel_queue.GetUpEnd()->TryDequeue();
+  EXPECT_NE(packet_view, nullptr);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl.h b/gd/l2cap/internal/channel_impl.h
new file mode 100644
index 0000000..ae17660
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl.h
@@ -0,0 +1,61 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/l2cap_packets.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+class Sender;
+
+/**
+ * Common interface for internal channel implementation
+ */
+class ChannelImpl {
+ public:
+  virtual ~ChannelImpl() = default;
+
+  /**
+   * Return the queue end for upper layer (L2CAP user)
+   */
+  virtual common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+  GetQueueUpEnd() = 0;
+
+  /**
+   * Return the queue end for lower layer (sender and receiver)
+   */
+  virtual common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*
+  GetQueueDownEnd() = 0;
+
+  virtual Cid GetCid() const = 0;
+
+  virtual Cid GetRemoteCid() const = 0;
+
+  /**
+   * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
+   * configuration change to Sender.
+   * Fixed channel doesn't need to implement it, as it doesn't need to send config update to Sender.
+   */
+  virtual void SetSender(l2cap::internal::Sender* sender) = 0;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl_mock.h b/gd/l2cap/internal/channel_impl_mock.h
new file mode 100644
index 0000000..710e69a
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl_mock.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "l2cap/internal/channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockChannelImpl : public ChannelImpl {
+ public:
+  MOCK_METHOD((common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*),
+              GetQueueUpEnd, (), (override));
+  MOCK_METHOD((common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*),
+              GetQueueDownEnd, (), (override));
+  MOCK_METHOD(Cid, GetCid, (), (const, override));
+  MOCK_METHOD(Cid, GetRemoteCid, (), (const, override));
+  MOCK_METHOD(void, SetSender, (l2cap::internal::Sender*), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/data_controller.h b/gd/l2cap/internal/data_controller.h
new file mode 100644
index 0000000..33bfbcf
--- /dev/null
+++ b/gd/l2cap/internal/data_controller.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <memory>
+
+#include "l2cap/l2cap_packets.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class DataController {
+ public:
+  virtual ~DataController() = default;
+
+  // SDU -> PDUs and notify Scheduler
+  virtual void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) = 0;
+
+  // PDUs -> SDU and enqueue to channel queue end
+  virtual void OnPdu(BasicFrameView pdu) = 0;
+
+  // Used by Scheduler to get next PDU
+  virtual std::unique_ptr<BasicFrameBuilder> GetNextPacket() = 0;
+
+  // Set FCS mode. This only applies to some modes (ERTM).
+  virtual void EnableFcs(bool enabled) = 0;
+
+  // Set retransmission and flow control. Ignore the mode option because each DataController only handles one mode.
+  // This only applies to some modes (ERTM).
+  virtual void SetRetransmissionAndFlowControlOptions(
+      const RetransmissionAndFlowControlConfigurationOption& option) = 0;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
new file mode 100644
index 0000000..08a4bbe
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
@@ -0,0 +1,909 @@
+/*
+ * 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/enhanced_retransmission_mode_channel_data_controller.h"
+
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "common/bind.h"
+#include "os/alarm.h"
+#include "packet/fragmenting_inserter.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+ErtmController::ErtmController(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),
+      pimpl_(std::make_unique<impl>(this, handler)) {}
+
+ErtmController::~ErtmController() = default;
+
+struct ErtmController::impl {
+  impl(ErtmController* controller, os::Handler* handler)
+      : controller_(controller), handler_(handler), retrans_timer_(handler), monitor_timer_(handler) {}
+
+  ErtmController* controller_;
+  os::Handler* handler_;
+
+  // We don't support extended window
+  static constexpr uint8_t kMaxTxWin = 64;
+
+  // We don't support sending SREJ
+  static constexpr bool kSendSrej = false;
+
+  // States (@see 8.6.5.2): Transmitter state and receiver state
+
+  enum class TxState {
+    XMIT,
+    WAIT_F,
+  };
+  TxState tx_state_ = TxState::XMIT;
+
+  enum class RxState {
+    RECV,
+    REJ_SENT,
+    SREJ_SENT,
+  };
+  RxState rx_state_ = RxState::RECV;
+
+  // Variables and Timers (@see 8.6.5.3)
+
+  uint8_t tx_seq_ = 0;
+  uint8_t next_tx_seq_ = 0;
+  uint8_t expected_ack_seq_ = 0;
+  uint8_t req_seq_ = 0;
+  uint8_t expected_tx_seq_ = 0;
+  uint8_t buffer_seq_ = 0;
+
+  bool remote_busy_ = false;
+  bool local_busy_ = false;
+  int unacked_frames_ = 0;
+  // TODO: Instead of having a map, we may consider about a better data structure
+  // Map from TxSeq to (SAR, SDU size for START packet, information payload)
+  std::map<uint8_t, std::tuple<SegmentationAndReassembly, uint16_t, std::shared_ptr<packet::RawBuilder>>> unacked_list_;
+  // Stores (SAR, SDU size for START packet, information payload)
+  std::queue<std::tuple<SegmentationAndReassembly, uint16_t, std::unique_ptr<packet::RawBuilder>>> pending_frames_;
+  int retry_count_ = 0;
+  std::map<uint8_t /* tx_seq, */, int /* count */> retry_i_frames_;
+  bool rnr_sent_ = false;
+  bool rej_actioned_ = false;
+  bool srej_actioned_ = false;
+  uint16_t srej_save_req_seq_ = 0;
+  bool send_rej_ = false;
+  int buffer_seq_srej_ = 0;
+  int frames_sent_ = 0;
+  os::Alarm retrans_timer_;
+  os::Alarm monitor_timer_;
+
+  // Events (@see 8.6.5.4)
+
+  void data_request(SegmentationAndReassembly sar, std::unique_ptr<packet::RawBuilder> pdu, uint16_t sdu_size = 0) {
+    // Note: sdu_size only applies to START packet
+    if (tx_state_ == TxState::XMIT && !remote_busy() && rem_window_not_full()) {
+      send_data(sar, sdu_size, std::move(pdu));
+    } else if (tx_state_ == TxState::XMIT && (remote_busy() || rem_window_full())) {
+      pend_data(sar, sdu_size, std::move(pdu));
+    } else if (tx_state_ == TxState::WAIT_F) {
+      pend_data(sar, sdu_size, std::move(pdu));
+    }
+  }
+
+  void local_busy_detected() {
+    local_busy_ = true;
+  }
+
+  void local_busy_clear() {
+    if (tx_state_ == TxState::XMIT && rnr_sent()) {
+      local_busy_ = false;
+      rnr_sent_ = false;
+      send_rr(Poll::POLL);
+      retry_count_ = 1;
+      stop_retrans_timer();
+      start_monitor_timer();
+    } else if (tx_state_ == TxState::XMIT) {
+      local_busy_ = false;
+      rnr_sent_ = false;
+    }
+  }
+
+  void recv_req_seq_and_f_bit(uint8_t req_seq, Final f) {
+    if (tx_state_ == TxState::XMIT) {
+      process_req_seq(req_seq);
+    } else if (f == Final::POLL_RESPONSE) {
+      process_req_seq(req_seq);
+      stop_monitor_timer();
+      if (unacked_frames_ > 0) {
+        start_retrans_timer();
+      }
+      tx_state_ = TxState::XMIT;
+    } else {
+      process_req_seq(req_seq);
+    }
+  }
+
+  void recv_f_bit(Final f) {
+    if (tx_state_ == TxState::WAIT_F && f == Final::POLL_RESPONSE) {
+      stop_monitor_timer();
+      if (unacked_frames_ > 0) {
+        start_retrans_timer();
+      }
+      tx_state_ = TxState::XMIT;
+    }
+  }
+
+  void retrans_timer_expires() {
+    if (tx_state_ == TxState::XMIT) {
+      send_rr_or_rnr(Poll::POLL);
+      // send rr or rnr(p=1)
+      retry_count_ = 1;
+      start_retrans_timer();
+      tx_state_ = TxState::WAIT_F;
+    }
+  }
+
+  void monitor_timer_expires() {
+    if (tx_state_ == TxState::WAIT_F && retry_count_less_than_max_transmit()) {
+      retry_count_++;
+      send_rr_or_rnr(Poll::POLL);
+      start_monitor_timer();
+    } else if (tx_state_ == TxState::WAIT_F) {
+      CloseChannel();
+    }
+  }
+
+  void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar,
+                    const packet::PacketView<true>& payload) {
+    if (rx_state_ == RxState::RECV) {
+      if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) &&
+          !local_busy()) {
+        increment_expected_tx_seq();
+        pass_to_tx(req_seq, f);
+        data_indication(sar, payload);
+        send_ack(Final::NOT_SET);
+      } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) &&
+                 with_valid_f_bit(f) && !local_busy()) {
+        increment_expected_tx_seq();
+        pass_to_tx(req_seq, f);
+        data_indication(sar, payload);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq);
+          send_pending_i_frames();
+        } else {
+          rej_actioned_ = false;
+        }
+        send_ack(Final::NOT_SET);
+      } else if (with_duplicate_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) {
+        pass_to_tx(req_seq, f);
+      } else if (with_unexpected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) &&
+                 !local_busy()) {
+        if constexpr (kSendSrej) {
+          // We don't support sending SREJ
+        } else {
+          pass_to_tx(req_seq, f);
+          send_rej();
+          rx_state_ = RxState::REJ_SENT;
+        }
+      } else if (with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && local_busy()) {
+        pass_to_tx(req_seq, f);
+        store_or_ignore();
+      } else if (with_valid_req_seq(req_seq) && not_with_expected_tx_seq(tx_seq) && with_valid_f_bit(f) &&
+                 local_busy()) {
+        pass_to_tx(req_seq, f);
+      } else if ((with_invalid_tx_seq(tx_seq) && controller_->local_tx_window_ > kMaxTxWin / 2) ||
+                 with_invalid_req_seq(req_seq)) {
+        CloseChannel();
+      } else if (with_invalid_tx_seq(tx_seq) && controller_->local_tx_window_ <= kMaxTxWin / 2) {
+        // We decided to ignore
+      }
+    } else if (rx_state_ == RxState::REJ_SENT) {
+      if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        increment_expected_tx_seq();
+        pass_to_tx(req_seq, f);
+        data_indication(sar, payload);
+        send_ack(Final::NOT_SET);
+        rx_state_ = RxState::RECV;
+      } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) &&
+                 with_valid_f_bit(f)) {
+        increment_expected_tx_seq();
+        pass_to_tx(req_seq, f);
+        data_indication(sar, payload);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq);
+          send_pending_i_frames();
+        } else {
+          rej_actioned_ = false;
+        }
+        send_ack(Final::NOT_SET);
+        rx_state_ = RxState::RECV;
+      } else if (with_unexpected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        pass_to_tx(req_seq, f);
+      }
+    } else if (rx_state_ == RxState::SREJ_SENT) {
+      // SREJ NOT SUPPORTED
+    }
+  }
+
+  void recv_rr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    if (rx_state_ == RxState::RECV) {
+      if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        pass_to_tx(req_seq, f);
+        if (remote_busy() && unacked_frames_ > 0) {
+          start_retrans_timer();
+        }
+        remote_busy_ = false;
+        send_pending_i_frames();
+      } else if (f == Final::POLL_RESPONSE && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq, p);
+        } else {
+          rej_actioned_ = false;
+        }
+        send_pending_i_frames();
+      } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        pass_to_tx(req_seq, f);
+        send_i_or_rr_or_rnr(Final::POLL_RESPONSE);
+      } else if (with_invalid_req_seq(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::REJ_SENT) {
+      if (f == Final::POLL_RESPONSE && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq, p);
+        } else {
+          rej_actioned_ = false;
+        }
+        send_pending_i_frames();
+      } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        pass_to_tx(req_seq, f);
+        if (remote_busy() and unacked_frames_ > 0) {
+          start_retrans_timer();
+        }
+        remote_busy_ = false;
+        send_ack(Final::NOT_SET);
+      } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        pass_to_tx(req_seq, f);
+        if (remote_busy() and unacked_frames_ > 0) {
+          start_retrans_timer();
+        }
+        remote_busy_ = false;
+        send_rr(Final::POLL_RESPONSE);
+      } else if (with_invalid_req_seq(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::SREJ_SENT) {
+      // SREJ NOT SUPPORTED
+    }
+  }
+
+  void recv_rej(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    if (rx_state_ == RxState::RECV) {
+      if (f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+          retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        retransmit_i_frames(req_seq, p);
+        send_pending_i_frames();
+        if (p_bit_outstanding()) {
+          rej_actioned_ = true;
+        }
+      } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq, p);
+        } else {
+          rej_actioned_ = false;
+        }
+        send_pending_i_frames();
+      } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+        CloseChannel();
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::REJ_SENT) {
+      if (f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+          retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        retransmit_i_frames(req_seq, p);
+        send_pending_i_frames();
+        if (p_bit_outstanding()) {
+          rej_actioned_ = true;
+        }
+      } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        if (!rej_actioned_) {
+          retransmit_i_frames(req_seq, p);
+        } else {
+          rej_actioned_ = false;
+        }
+        send_pending_i_frames();
+      } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+        CloseChannel();
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::SREJ_SENT) {
+      // SREJ NOT SUPPORTED
+    }
+  }
+
+  void recv_rnr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    if (rx_state_ == RxState::RECV) {
+      if (p == Poll::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = true;
+        pass_to_tx(req_seq, f);
+        stop_retrans_timer();
+      } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = true;
+        pass_to_tx(req_seq, f);
+        stop_retrans_timer();
+        send_rr_or_rnr(Poll::NOT_SET, Final::POLL_RESPONSE);
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::REJ_SENT) {
+      if (p == Poll::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = true;
+        pass_to_tx(req_seq, f);
+        send_rr(Final::POLL_RESPONSE);
+      } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = true;
+        pass_to_tx(req_seq, f);
+        send_rr(Final::NOT_SET);
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::SREJ_SENT) {
+      // SREJ NOT SUPPORTED
+    }
+  }
+
+  void recv_srej(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    if (rx_state_ == RxState::RECV) {
+      if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+          retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx_f_bit(f);
+        retransmit_requested_i_frame(req_seq, p);
+        if (p_bit_outstanding()) {
+          srej_actioned_ = true;
+          srej_save_req_seq_ = req_seq;
+        }
+      } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx_f_bit(f);
+        if (srej_actioned_ && srej_save_req_seq_ == req_seq) {
+          srej_actioned_ = false;
+        } else {
+          retransmit_requested_i_frame(req_seq, p);
+        }
+      } else if (p == Poll::POLL && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        retransmit_requested_i_frame(req_seq, p);
+        if (p_bit_outstanding()) {
+          srej_actioned_ = true;
+          srej_save_req_seq_ = req_seq;
+        }
+      } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+        CloseChannel();
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::REJ_SENT) {
+      if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+          retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx_f_bit(f);
+        retransmit_requested_i_frame(req_seq, p);
+        if (p_bit_outstanding()) {
+          srej_actioned_ = true;
+          srej_save_req_seq_ = req_seq;
+        }
+      } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx_f_bit(f);
+        if (srej_actioned_ && srej_save_req_seq_ == req_seq) {
+          srej_actioned_ = false;
+        } else {
+          retransmit_requested_i_frame(req_seq, p);
+        }
+      } else if (p == Poll::POLL && with_valid_req_seq_retrans(req_seq) &&
+                 retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+        remote_busy_ = false;
+        pass_to_tx(req_seq, f);
+        retransmit_requested_i_frame(req_seq, p);
+        send_pending_i_frames();
+        if (p_bit_outstanding()) {
+          srej_actioned_ = true;
+          srej_save_req_seq_ = req_seq;
+        }
+      } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+        CloseChannel();
+      } else if (with_invalid_req_seq_retrans(req_seq)) {
+        CloseChannel();
+      }
+    } else if (rx_state_ == RxState::SREJ_SENT) {
+      // SREJ NOT SUPPORTED
+    }
+  }
+
+  // Conditions (@see 8.6.5.5)
+  bool remote_busy() {
+    return remote_busy_;
+  }
+
+  bool local_busy() {
+    return local_busy_;
+  }
+
+  bool rem_window_not_full() {
+    return unacked_frames_ < controller_->remote_tx_window_;
+  }
+
+  bool rem_window_full() {
+    return unacked_frames_ == controller_->remote_tx_window_;
+  }
+
+  bool rnr_sent() {
+    return rnr_sent_;
+  }
+
+  bool retry_i_frames_less_than_max_transmit(uint8_t req_seq) {
+    return retry_i_frames_[req_seq] < controller_->local_max_transmit_;
+  }
+
+  bool retry_count_less_than_max_transmit() {
+    return retry_count_ < controller_->local_max_transmit_;
+  }
+
+  bool with_expected_tx_seq(uint8_t tx_seq) {
+    return tx_seq == expected_tx_seq_;
+  }
+
+  bool with_valid_req_seq(uint8_t req_seq) {
+    return expected_ack_seq_ <= req_seq && req_seq <= next_tx_seq_;
+  }
+
+  bool with_valid_req_seq_retrans(uint8_t req_seq) {
+    return expected_ack_seq_ <= req_seq && req_seq <= next_tx_seq_;
+  }
+
+  bool with_valid_f_bit(Final f) {
+    return f == Final::NOT_SET || tx_state_ == TxState::WAIT_F;
+  }
+
+  bool with_unexpected_tx_seq(uint8_t tx_seq) {
+    return tx_seq > expected_tx_seq_ && tx_seq <= expected_tx_seq_ + controller_->local_tx_window_;
+  }
+
+  bool with_duplicate_tx_seq(uint8_t tx_seq) {
+    return tx_seq < expected_tx_seq_ && tx_seq >= expected_tx_seq_ - controller_->local_tx_window_;
+  }
+
+  bool with_invalid_tx_seq(uint8_t tx_seq) {
+    return tx_seq < expected_tx_seq_ - controller_->local_tx_window_ ||
+           tx_seq > expected_tx_seq_ + controller_->local_tx_window_;
+  }
+
+  bool with_invalid_req_seq(uint8_t req_seq) {
+    return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_;
+  }
+
+  bool with_invalid_req_seq_retrans(uint8_t req_seq) {
+    return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_;
+  }
+
+  bool not_with_expected_tx_seq(uint8_t tx_seq) {
+    return !with_invalid_tx_seq(tx_seq) && !with_expected_tx_seq(tx_seq);
+  }
+
+  bool with_expected_tx_seq_srej() {
+    // We don't support sending SREJ
+    return false;
+  }
+
+  bool send_req_is_true() {
+    // We don't support sending SREJ
+    return false;
+  }
+
+  bool srej_list_is_one() {
+    // We don't support sending SREJ
+    return false;
+  }
+
+  bool with_unexpected_tx_seq_srej() {
+    // We don't support sending SREJ
+    return false;
+  }
+
+  bool with_duplicate_tx_seq_srej() {
+    // We don't support sending SREJ
+    return false;
+  }
+
+  // Actions (@see 8.6.5.6)
+
+  void _send_i_frame(SegmentationAndReassembly sar, std::unique_ptr<CopyablePacketBuilder> segment, uint8_t req_seq,
+                     uint8_t tx_seq, uint16_t sdu_size = 0, Final f = Final::NOT_SET) {
+    std::unique_ptr<EnhancedInformationFrameBuilder> builder;
+    if (sar == SegmentationAndReassembly::START) {
+      builder = EnhancedInformationStartFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sdu_size,
+                                                             std::move(segment));
+    } else {
+      builder = EnhancedInformationFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sar,
+                                                        std::move(segment));
+    }
+    controller_->send_pdu(std::move(builder));
+  }
+
+  void send_data(SegmentationAndReassembly sar, uint16_t sdu_size, std::unique_ptr<packet::RawBuilder> segment,
+                 Final f = Final::NOT_SET) {
+    std::shared_ptr<packet::RawBuilder> shared_segment(segment.release());
+    unacked_list_.emplace(std::piecewise_construct, std::forward_as_tuple(next_tx_seq_),
+                          std::forward_as_tuple(sar, sdu_size, shared_segment));
+
+    std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+        std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(next_tx_seq_)->second));
+    _send_i_frame(sar, std::move(copyable_packet_builder), buffer_seq_, next_tx_seq_, sdu_size, f);
+    // TODO hsz fix me
+    unacked_frames_++;
+    frames_sent_++;
+    retry_i_frames_[next_tx_seq_] = 1;
+    next_tx_seq_ = (next_tx_seq_ + 1) % kMaxTxWin;
+    start_retrans_timer();
+  }
+
+  void pend_data(SegmentationAndReassembly sar, uint16_t sdu_size, std::unique_ptr<packet::RawBuilder> data) {
+    pending_frames_.emplace(std::make_tuple(sar, sdu_size, std::move(data)));
+  }
+
+  void process_req_seq(uint8_t req_seq) {
+    for (int i = expected_ack_seq_; i < req_seq; i++) {
+      unacked_list_.erase(i);
+      retry_i_frames_[i] = 0;
+    }
+    unacked_frames_ -= ((req_seq - expected_ack_seq_) + kMaxTxWin) % kMaxTxWin;
+    if (unacked_frames_ == 0) {
+      stop_retrans_timer();
+    }
+  }
+
+  void _send_s_frame(SupervisoryFunction s, uint8_t req_seq, Poll p, Final f) {
+    auto builder = EnhancedSupervisoryFrameBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
+    controller_->send_pdu(std::move(builder));
+  }
+
+  void send_rr(Poll p) {
+    _send_s_frame(SupervisoryFunction::RECEIVER_READY, expected_tx_seq_, p, Final::NOT_SET);
+  }
+
+  void send_rr(Final f) {
+    _send_s_frame(SupervisoryFunction::RECEIVER_READY, expected_tx_seq_, Poll::NOT_SET, f);
+  }
+
+  void send_rnr(Poll p) {
+    _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, expected_tx_seq_, p, Final::NOT_SET);
+  }
+
+  void send_rnr(Final f) {
+    _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, expected_tx_seq_, Poll::NOT_SET, f);
+  }
+
+  void send_rej(Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    _send_s_frame(SupervisoryFunction::REJECT, expected_tx_seq_, p, f);
+  }
+
+  void send_rr_or_rnr(Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+    if (local_busy()) {
+      _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, buffer_seq_, p, f);
+    } else {
+      _send_s_frame(SupervisoryFunction::RECEIVER_READY, buffer_seq_, p, f);
+    }
+  }
+
+  void send_i_or_rr_or_rnr(Final f = Final::POLL_RESPONSE) {
+    auto frames_sent = 0;
+    if (local_busy()) {
+      send_rnr(Final::POLL_RESPONSE);
+    }
+    if (remote_busy() && unacked_frames_ > 0) {
+      start_retrans_timer();
+    }
+    remote_busy_ = false;
+    send_pending_i_frames(f);  // TODO: Only first has f = 1, other f = 0. Also increase frames_sent
+    if (!local_busy() && frames_sent == 0) {
+      send_rr(Final::POLL_RESPONSE);
+    }
+  }
+
+  void send_srej() {
+    // Sending SREJ is not supported
+  }
+
+  void start_retrans_timer() {
+    retrans_timer_.Schedule(common::BindOnce(&impl::retrans_timer_expires, common::Unretained(this)),
+                            std::chrono::milliseconds(controller_->local_retransmit_timeout_ms_));
+  }
+
+  void start_monitor_timer() {
+    monitor_timer_.Schedule(common::BindOnce(&impl::monitor_timer_expires, common::Unretained(this)),
+                            std::chrono::milliseconds(controller_->local_monitor_timeout_ms_));
+  }
+
+  void pass_to_tx(uint8_t req_seq, Final f) {
+    recv_req_seq_and_f_bit(req_seq, f);
+  }
+
+  void pass_to_tx_f_bit(Final f) {
+    recv_f_bit(f);
+  }
+
+  void data_indication(SegmentationAndReassembly sar, const packet::PacketView<true>& segment) {
+    controller_->stage_for_reassembly(sar, segment);
+    buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin;
+  }
+
+  void increment_expected_tx_seq() {
+    expected_tx_seq_ = (expected_tx_seq_ + 1) % kMaxTxWin;
+  }
+
+  void stop_retrans_timer() {
+    retrans_timer_.Cancel();
+  }
+
+  void stop_monitor_timer() {
+    monitor_timer_.Cancel();
+  }
+
+  void send_ack(Final f = Final::NOT_SET) {
+    if (local_busy()) {
+      send_rnr(f);
+    } else if (!remote_busy() && /* pending i frames exist */ rem_window_not_full()) {
+      send_pending_i_frames(f);
+    } else {
+      send_rr(f);
+    }
+  }
+
+  void init_srej() {
+    // We don't support sending SREJ
+  }
+
+  void save_i_frame_srej() {
+    // We don't support sending SREJ
+  }
+
+  void store_or_ignore() {
+    // We choose to ignore. We don't support local busy so far.
+  }
+
+  bool p_bit_outstanding() {
+    return tx_state_ == TxState::WAIT_F;
+  }
+
+  void retransmit_i_frames(uint8_t req_seq, Poll p = Poll::NOT_SET) {
+    uint8_t i = req_seq;
+    Final f = (p == Poll::NOT_SET ? Final::NOT_SET : Final::POLL_RESPONSE);
+    while (unacked_list_.find(i) == unacked_list_.end()) {
+      std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+          std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(i)->second));
+      _send_i_frame(std::get<0>(unacked_list_.find(i)->second), std::move(copyable_packet_builder), buffer_seq_, i,
+                    std::get<1>(unacked_list_.find(i)->second), f);
+      retry_i_frames_[i]++;
+      if (retry_i_frames_[i] == controller_->local_max_transmit_) {
+        CloseChannel();
+      }
+      frames_sent_++;
+      f = Final::NOT_SET;
+    }
+    start_retrans_timer();
+  }
+
+  void retransmit_requested_i_frame(uint8_t req_seq, Poll p) {
+    Final f = p == Poll::POLL ? Final::POLL_RESPONSE : Final::NOT_SET;
+    if (unacked_list_.find(req_seq) == unacked_list_.end()) {
+      LOG_ERROR("Received invalid SREJ");
+      return;
+    }
+    std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+        std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(req_seq)->second));
+    _send_i_frame(std::get<0>(unacked_list_.find(req_seq)->second), std::move(copyable_packet_builder), buffer_seq_,
+                  req_seq, std::get<1>(unacked_list_.find(req_seq)->second), f);
+    retry_i_frames_[req_seq]++;
+    start_retrans_timer();
+  }
+
+  void send_pending_i_frames(Final f = Final::NOT_SET) {
+    if (p_bit_outstanding()) {
+      return;
+    }
+    while (rem_window_not_full() && !pending_frames_.empty()) {
+      auto& frame = pending_frames_.front();
+      send_data(std::get<0>(frame), std::get<1>(frame), std::move(std::get<2>(frame)), f);
+      pending_frames_.pop();
+      f = Final::NOT_SET;
+    }
+  }
+
+  void CloseChannel() {
+    // TODO: Needs a reference to signaller
+  }
+
+  void pop_srej_list() {
+    // We don't support sending SREJ
+  }
+
+  void data_indication_srej() {
+    // We don't support sending SREJ
+  }
+};
+
+// Segmentation is handled here
+void ErtmController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
+  // TODO: Optimize the calculation. We don't need to count for SDU length in CONTINUATION or END packets. We don't need
+  // to FCS when disabled.
+  size_t size_each_packet =
+      (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */);
+  auto sdu_size = sdu->size();
+  std::vector<std::unique_ptr<packet::RawBuilder>> segments;
+  packet::FragmentingInserter fragmenting_inserter(size_each_packet, std::back_insert_iterator(segments));
+  sdu->Serialize(fragmenting_inserter);
+  fragmenting_inserter.finalize();
+  if (segments.size() == 1) {
+    pimpl_->data_request(SegmentationAndReassembly::UNSEGMENTED, std::move(segments[0]));
+    return;
+  }
+  pimpl_->data_request(SegmentationAndReassembly::START, std::move(segments[0]), sdu_size);
+  for (auto i = 1; i < segments.size() - 1; i++) {
+    pimpl_->data_request(SegmentationAndReassembly::CONTINUATION, std::move(segments[i]));
+  }
+  pimpl_->data_request(SegmentationAndReassembly::END, std::move(segments.back()));
+}
+
+void ErtmController::OnPdu(BasicFrameView pdu) {
+  auto standard_frame_view = StandardFrameView::Create(pdu);
+  if (!standard_frame_view.IsValid()) {
+    LOG_WARN("Received invalid frame");
+    return;
+  }
+  auto type = standard_frame_view.GetFrameType();
+  if (type == FrameType::I_FRAME) {
+    auto i_frame_view = EnhancedInformationFrameView::Create(standard_frame_view);
+    if (!i_frame_view.IsValid()) {
+      LOG_WARN("Received invalid frame");
+      return;
+    }
+    pimpl_->recv_i_frame(i_frame_view.GetF(), i_frame_view.GetTxSeq(), i_frame_view.GetReqSeq(), i_frame_view.GetSar(),
+                         i_frame_view.GetPayload());
+  } else if (type == FrameType::S_FRAME) {
+    auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view);
+    if (!s_frame_view.IsValid()) {
+      LOG_WARN("Received invalid frame");
+      return;
+    }
+    auto req_seq = s_frame_view.GetReqSeq();
+    auto f = s_frame_view.GetF();
+    auto p = s_frame_view.GetP();
+    switch (s_frame_view.GetS()) {
+      case SupervisoryFunction::RECEIVER_READY:
+        pimpl_->recv_rr(req_seq, p, f);
+        break;
+      case SupervisoryFunction::RECEIVER_NOT_READY:
+        pimpl_->recv_rnr(req_seq, p, f);
+        break;
+      case SupervisoryFunction::REJECT:
+        pimpl_->recv_rej(req_seq, p, f);
+        break;
+      case SupervisoryFunction::SELECT_REJECT:
+        pimpl_->recv_srej(req_seq, p, f);
+        break;
+    }
+  } else {
+    LOG_WARN("Received invalid frame");
+  }
+}
+
+std::unique_ptr<BasicFrameBuilder> ErtmController::GetNextPacket() {
+  auto next = std::move(pdu_queue_.front());
+  pdu_queue_.pop();
+  return next;
+}
+
+void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar,
+                                          const packet::PacketView<kLittleEndian>& payload) {
+  switch (sar) {
+    case SegmentationAndReassembly::UNSEGMENTED:
+      enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_);
+      break;
+    case SegmentationAndReassembly::START:
+      if (sar_state_ != SegmentationAndReassembly::END) {
+        LOG_WARN("Received invalid SAR");
+        close_channel();
+        return;
+      }
+      sar_state_ = SegmentationAndReassembly::START;
+      reassembly_stage_ = payload;
+      break;
+    case SegmentationAndReassembly::CONTINUATION:
+      if (sar_state_ == SegmentationAndReassembly::END) {
+        LOG_WARN("Received invalid SAR");
+        close_channel();
+        return;
+      }
+      reassembly_stage_.AppendPacketView(payload);
+      break;
+    case SegmentationAndReassembly::END:
+      if (sar_state_ == SegmentationAndReassembly::END) {
+        LOG_WARN("Received invalid SAR");
+        close_channel();
+        return;
+      }
+      reassembly_stage_.AppendPacketView(payload);
+      enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_);
+      sar_state_ = SegmentationAndReassembly::END;
+      break;
+  }
+}
+
+void ErtmController::EnableFcs(bool enabled) {
+  fcs_enabled_ = enabled;
+}
+
+void ErtmController::send_pdu(std::unique_ptr<BasicFrameBuilder> pdu) {
+  pdu_queue_.emplace(std::move(pdu));
+  scheduler_->OnPacketsReady(cid_, 1);
+}
+
+void ErtmController::SetRetransmissionAndFlowControlOptions(
+    const RetransmissionAndFlowControlConfigurationOption& option) {
+  local_tx_window_ = option.tx_window_size_;
+  local_max_transmit_ = option.max_transmit_;
+  local_retransmit_timeout_ms_ = option.retransmission_time_out_;
+  local_monitor_timeout_ms_ = option.monitor_time_out_;
+}
+
+void ErtmController::close_channel() {
+  // TODO: Get a reference to signalling manager
+}
+
+size_t ErtmController::CopyablePacketBuilder::size() const {
+  return builder_->size();
+}
+
+void ErtmController::CopyablePacketBuilder::Serialize(BitInserter& it) const {
+  builder_->Serialize(it);
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
new file mode 100644
index 0000000..2038fd3
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
@@ -0,0 +1,107 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class ErtmController : public DataController {
+ public:
+  using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+  using UpperDequeue = packet::BasePacketBuilder;
+  using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+  ErtmController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+                 Scheduler* scheduler);
+  ~ErtmController();
+  // Segmentation is handled here
+  void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
+  void OnPdu(BasicFrameView pdu) override;
+  std::unique_ptr<BasicFrameBuilder> GetNextPacket() override;
+  void EnableFcs(bool enabled) override;
+  void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override;
+
+ private:
+  Cid cid_;
+  Cid remote_cid_;
+  os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+  os::Handler* handler_;
+  std::queue<std::unique_ptr<BasicFrameBuilder>> pdu_queue_;
+  Scheduler* scheduler_;
+  bool fcs_enabled_ = false;
+
+  class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
+   public:
+    PacketViewForReassembly(const PacketView& packetView) : PacketView(packetView) {}
+    void AppendPacketView(packet::PacketView<kLittleEndian> to_append) {
+      Append(to_append);
+    }
+  };
+
+  class CopyablePacketBuilder : public packet::BasePacketBuilder {
+   public:
+    CopyablePacketBuilder(std::shared_ptr<packet::RawBuilder> builder) : builder_(std::move(builder)) {}
+
+    void Serialize(BitInserter& it) const override;
+
+    size_t size() const override;
+
+   private:
+    std::shared_ptr<packet::RawBuilder> builder_;
+  };
+
+  PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()};
+  SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END;
+
+  void stage_for_reassembly(SegmentationAndReassembly sar, const packet::PacketView<kLittleEndian>& payload);
+  void send_pdu(std::unique_ptr<BasicFrameBuilder> pdu);
+
+  void close_channel();
+
+  // Configuration options
+  uint16_t local_tx_window_ = 10;
+  uint16_t local_max_transmit_ = 20;
+  uint16_t local_retransmit_timeout_ms_ = 2000;
+  uint16_t local_monitor_timeout_ms_ = 12000;
+
+  uint16_t remote_tx_window_ = 10;
+  uint16_t remote_mps_ = 1010;
+
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc
new file mode 100644
index 0000000..dd87e36
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc
@@ -0,0 +1,94 @@
+/*
+ * 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/enhanced_retransmission_mode_channel_data_controller.h"
+
+#include <gtest/gtest.h>
+
+#include "l2cap/internal/scheduler_mock.h"
+#include "l2cap/l2cap_packets.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;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+  auto status = future.wait_for(std::chrono::milliseconds(300));
+  EXPECT_EQ(status, std::future_status::ready);
+}
+
+class ErtmDataControllerTest : public ::testing::Test {
+ 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_);
+  }
+
+  void TearDown() override {
+    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;
+};
+
+TEST_F(ErtmDataControllerTest, receive) {
+  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+  testing::MockScheduler scheduler;
+  ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+  auto segment = CreateSdu({'a', 'b', 'c', 'd'});
+  auto builder = EnhancedInformationFrameBuilder::Create(1, 0, Final::NOT_SET, 0,
+                                                         SegmentationAndReassembly::UNSEGMENTED, std::move(segment));
+  auto base_view = GetPacketView(std::move(builder));
+  auto basic_frame_view = BasicFrameView::Create(base_view);
+  EXPECT_TRUE(basic_frame_view.IsValid());
+  controller.OnPdu(basic_frame_view);
+  sync_handler(queue_handler_);
+  auto payload = channel_queue.GetUpEnd()->TryDequeue();
+  EXPECT_NE(payload, nullptr);
+  std::string data = std::string(payload->begin(), payload->end());
+  EXPECT_EQ(data, "abcd");
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/fixed_channel_allocator.h b/gd/l2cap/internal/fixed_channel_allocator.h
new file mode 100644
index 0000000..a421c91
--- /dev/null
+++ b/gd/l2cap/internal/fixed_channel_allocator.h
@@ -0,0 +1,102 @@
+/*
+ * 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 <type_traits>
+#include <unordered_map>
+
+#include "hci/hci_packets.h"
+#include "l2cap/cid.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+// Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
+// channel is in use
+template <typename FixedChannelImplType, typename LinkType>
+class FixedChannelAllocator {
+ public:
+  FixedChannelAllocator(LinkType* link, os::Handler* l2cap_handler) : link_(link), l2cap_handler_(l2cap_handler) {
+    ASSERT(link_ != nullptr);
+    ASSERT(l2cap_handler_ != nullptr);
+  }
+
+  virtual ~FixedChannelAllocator() = default;
+
+  // Allocates a channel. If cid is used, return nullptr. NOTE: The returned BaseFixedChannelImpl object is still
+  // owned by the channel allocator, NOT the client.
+  virtual std::shared_ptr<FixedChannelImplType> AllocateChannel(Cid cid, SecurityPolicy security_policy) {
+    ASSERT_LOG(!IsChannelAllocated((cid)), "Cid 0x%x for device %s is already in use", cid,
+               link_->GetDevice().ToString().c_str());
+    ASSERT_LOG(cid >= kFirstFixedChannel && cid <= kLastFixedChannel, "Cid %d out of bound", cid);
+    auto elem = channels_.try_emplace(cid, std::make_shared<FixedChannelImplType>(cid, link_, l2cap_handler_));
+    ASSERT_LOG(elem.second, "Failed to create channel for cid 0x%x device %s", cid,
+               link_->GetDevice().ToString().c_str());
+    ASSERT(elem.first->second != nullptr);
+    return elem.first->second;
+  }
+
+  // Frees a channel. If cid doesn't exist, it will crash
+  virtual void FreeChannel(Cid cid) {
+    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
+               link_->GetDevice().ToString().c_str());
+    channels_.erase(cid);
+  }
+
+  virtual bool IsChannelAllocated(Cid cid) const {
+    return channels_.find(cid) != channels_.end();
+  }
+
+  virtual std::shared_ptr<FixedChannelImplType> FindChannel(Cid cid) {
+    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
+               link_->GetDevice().ToString().c_str());
+    return channels_.find(cid)->second;
+  }
+
+  virtual size_t NumberOfChannels() const {
+    return channels_.size();
+  }
+
+  virtual void OnAclDisconnected(hci::ErrorCode hci_status) {
+    for (auto& elem : channels_) {
+      elem.second->OnClosed(hci_status);
+    }
+  }
+
+  virtual int GetRefCount() {
+    int ref_count = 0;
+    for (auto& elem : channels_) {
+      if (elem.second->IsAcquired()) {
+        ref_count++;
+      }
+    }
+    return ref_count;
+  }
+
+ private:
+  LinkType* link_;
+  os::Handler* l2cap_handler_;
+  std::unordered_map<Cid, std::shared_ptr<FixedChannelImplType>> channels_;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/fixed_channel_allocator_test.cc b/gd/l2cap/internal/fixed_channel_allocator_test.cc
new file mode 100644
index 0000000..2162d36
--- /dev/null
+++ b/gd/l2cap/internal/fixed_channel_allocator_test.cc
@@ -0,0 +1,81 @@
+/*
+ * 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/fixed_channel_allocator.h"
+#include "l2cap/classic/internal/fixed_channel_impl_mock.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+using l2cap::classic::internal::testing::MockFixedChannelImpl;
+using l2cap::classic::internal::testing::MockLink;
+using testing::MockParameterProvider;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capFixedChannelAllocatorTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+    mock_parameter_provider_ = new MockParameterProvider();
+    mock_classic_link_ = new MockLink(handler_, mock_parameter_provider_);
+    EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+    // Use classic as a place holder
+    channel_allocator_ =
+        std::make_unique<FixedChannelAllocator<MockFixedChannelImpl, MockLink>>(mock_classic_link_, handler_);
+  }
+
+  void TearDown() override {
+    channel_allocator_.reset();
+    delete mock_classic_link_;
+    delete mock_parameter_provider_;
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_{nullptr};
+  os::Handler* handler_{nullptr};
+  MockParameterProvider* mock_parameter_provider_{nullptr};
+  MockLink* mock_classic_link_{nullptr};
+  std::unique_ptr<FixedChannelAllocator<MockFixedChannelImpl, MockLink>> channel_allocator_;
+};
+
+TEST_F(L2capFixedChannelAllocatorTest, precondition) {
+  Cid cid = kFirstFixedChannel;
+  EXPECT_FALSE(channel_allocator_->IsChannelAllocated(cid));
+}
+
+TEST_F(L2capFixedChannelAllocatorTest, allocate_and_free_channel) {
+  Cid cid = kFirstFixedChannel;
+  auto channel = channel_allocator_->AllocateChannel(cid, {});
+  EXPECT_TRUE(channel_allocator_->IsChannelAllocated(cid));
+  EXPECT_EQ(channel, channel_allocator_->FindChannel(cid));
+  ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(cid));
+  EXPECT_FALSE(channel_allocator_->IsChannelAllocated(cid));
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/parameter_provider.h b/gd/l2cap/internal/parameter_provider.h
new file mode 100644
index 0000000..e1db944
--- /dev/null
+++ b/gd/l2cap/internal/parameter_provider.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <chrono>
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * A class that provide constant parameters to the L2CAP stack
+ *
+ * All methods are virtual so that they can be override in unit tests
+ */
+class ParameterProvider {
+ public:
+  virtual ~ParameterProvider() = default;
+  virtual std::chrono::milliseconds GetClassicLinkIdleDisconnectTimeout() {
+    return std::chrono::seconds(20);
+  }
+  virtual std::chrono::milliseconds GetLeLinkIdleDisconnectTimeout() {
+    return std::chrono::seconds(20);
+  }
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/facade.h b/gd/l2cap/internal/parameter_provider_mock.h
similarity index 62%
copy from gd/l2cap/facade.h
copy to gd/l2cap/internal/parameter_provider_mock.h
index 734d261..823cf8a 100644
--- a/gd/l2cap/facade.h
+++ b/gd/l2cap/internal/parameter_provider_mock.h
@@ -15,27 +15,23 @@
  */
 #pragma once
 
-#include <grpc++/grpc++.h>
-#include "grpc/grpc_module.h"
+#include "l2cap/internal/parameter_provider.h"
 
+#include <gmock/gmock.h>
+
+// Unit test interfaces
 namespace bluetooth {
 namespace l2cap {
+namespace internal {
+namespace testing {
 
-class L2capModuleFacadeService;
-
-class L2capModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+class MockParameterProvider : public ParameterProvider {
  public:
-  static const ModuleFactory Factory;
-
-  void ListDependencies(ModuleList* list) override;
-  void Start() override;
-  void Stop() override;
-
-  ::grpc::Service* GetService() const override;
-
- private:
-  L2capModuleFacadeService* service_;
+  MOCK_METHOD(std::chrono::milliseconds, GetClassicLinkIdleDisconnectTimeout, (), (override));
+  MOCK_METHOD(std::chrono::milliseconds, GetLeLinkIdleDisconnectTimeout, (), (override));
 };
 
+}  // namespace testing
+}  // namespace internal
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/internal/receiver.cc b/gd/l2cap/internal/receiver.cc
new file mode 100644
index 0000000..437064e
--- /dev/null
+++ b/gd/l2cap/internal/receiver.cc
@@ -0,0 +1,56 @@
+/*
+ * 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/receiver.h"
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+Receiver::Receiver(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler, Scheduler* scheduler)
+    : link_queue_up_end_(link_queue_up_end), handler_(handler), scheduler_(scheduler) {
+  ASSERT(link_queue_up_end_ != nullptr && handler_ != nullptr);
+  link_queue_up_end_->RegisterDequeue(handler_,
+                                      common::Bind(&Receiver::link_queue_dequeue_callback, common::Unretained(this)));
+}
+
+Receiver::~Receiver() {
+  link_queue_up_end_->UnregisterDequeue();
+}
+
+void Receiver::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* data_controller = scheduler_->GetDataController(cid);
+  if (data_controller == nullptr) {
+    LOG_WARN("Received a packet with invalid cid: %d", cid);
+    return;
+  }
+  data_controller->OnPdu(basic_frame_view);
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/receiver.h b/gd/l2cap/internal/receiver.h
new file mode 100644
index 0000000..e3c035e
--- /dev/null
+++ b/gd/l2cap/internal/receiver.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.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 receiving L2CAP PDUs from link queue and distribute them into into channel data controllers.
+ * 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.
+ * The Reassembler also keeps the reference to Scheduler, to get Segmenter and send signals (Tx, Rx seq) to it.
+ */
+class Receiver {
+ 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>;
+
+  Receiver(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler, Scheduler* scheduler);
+  ~Receiver();
+
+ private:
+  LowerQueueUpEnd* link_queue_up_end_;
+  os::Handler* handler_;
+  Scheduler* scheduler_;
+
+  void link_queue_dequeue_callback();
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/l2cap/internal/receiver_test.cc
similarity index 65%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/l2cap/internal/receiver_test.cc
index 8a08509..a401d22 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/l2cap/internal/receiver_test.cc
@@ -14,12 +14,23 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#include "l2cap/internal/receiver.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
 
 namespace bluetooth {
 namespace l2cap {
-
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
-
+namespace internal {
+namespace {}  // namespace
+}  // namespace internal
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler.h b/gd/l2cap/internal/scheduler.h
new file mode 100644
index 0000000..59f2bfd
--- /dev/null
+++ b/gd/l2cap/internal/scheduler.h
@@ -0,0 +1,86 @@
+/*
+ * 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 <cstdint>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/sender.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * 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).
+ *
+ * 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:
+  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>;
+
+  /**
+   * Attach the channel with the specified ChannelQueueDownEnd into the scheduler.
+   * Scheduler needs to notify the channel its Sender through SetSender().
+   *
+   * @param cid The channel to attach to the scheduler.
+   * @param channel The reference to a DynamicChannelImpl object. Use nullptr for fixed channel.
+   * TODO (b/144503952): Rethink about channel abstraction. Currently channel contains duplicated info as remote_cid
+   */
+  virtual void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {}
+
+  /**
+   * Detach the channel from the scheduler.
+   *
+   * @param cid The channel to detach to the scheduler.
+   */
+  virtual void DetachChannel(Cid cid) {}
+
+  /**
+   * Callback from the sender to indicate that the scheduler could dequeue number_packets from it
+   */
+  virtual void OnPacketsReady(Cid cid, int number_packets) {}
+
+  /**
+   * Get the data controller for Reassembler
+   */
+  virtual DataController* GetDataController(Cid cid) {
+    return nullptr;
+  }
+
+  virtual ~Scheduler() = default;
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc
new file mode 100644
index 0000000..7454cbe
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo.cc
@@ -0,0 +1,94 @@
+/*
+ * 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/scheduler_fifo.h"
+
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+
+namespace bluetooth {
+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() {
+  sender_map_.clear();
+  if (link_queue_enqueue_registered_) {
+    link_queue_up_end_->UnregisterEnqueue();
+  }
+}
+
+void Fifo::AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {
+  ASSERT(sender_map_.find(cid) == sender_map_.end());
+  sender_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
+                      std::forward_as_tuple(handler_, this, channel));
+  if (channel->GetCid() >= kFirstDynamicChannel) {
+    channel->SetSender(&sender_map_.find(cid)->second);
+  }
+}
+
+void Fifo::DetachChannel(Cid cid) {
+  ASSERT(sender_map_.find(cid) != sender_map_.end());
+  sender_map_.erase(cid);
+}
+
+void Fifo::OnPacketsReady(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_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();
+  }
+  auto packet = sender_map_.find(channel_id)->second.GetNextPacket();
+
+  sender_map_.find(channel_id)->second.OnPacketSent();
+  if (next_to_dequeue_and_num_packets.empty()) {
+    link_queue_up_end_->UnregisterEnqueue();
+    link_queue_enqueue_registered_ = false;
+  }
+  return packet;
+}
+
+void Fifo::try_register_link_queue_enqueue() {
+  if (link_queue_enqueue_registered_) {
+    return;
+  }
+  link_queue_up_end_->RegisterEnqueue(handler_,
+                                      common::Bind(&Fifo::link_queue_enqueue_callback, common::Unretained(this)));
+  link_queue_enqueue_registered_ = true;
+}
+
+DataController* Fifo::GetDataController(Cid cid) {
+  if (sender_map_.find(cid) == sender_map_.end()) {
+    return nullptr;
+  }
+  return sender_map_.find(cid)->second.GetDataController();
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.h b/gd/l2cap/internal/scheduler_fifo.h
new file mode 100644
index 0000000..b20ea4f
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo.h
@@ -0,0 +1,57 @@
+/*
+ * 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 "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/sender.h"
+#include "os/handler.h"
+#include "os/queue.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class Fifo : public Scheduler {
+ public:
+  Fifo(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler);
+  ~Fifo() override;
+  void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) override;
+  void DetachChannel(Cid cid) override;
+  void OnPacketsReady(Cid cid, int number_packets) override;
+  DataController* GetDataController(Cid cid) override;
+
+ private:
+  LowerQueueUpEnd* link_queue_up_end_;
+  os::Handler* handler_;
+  std::unordered_map<Cid, Sender> sender_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();
+  std::unique_ptr<LowerEnqueue> link_queue_enqueue_callback();
+};
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo_test.cc b/gd/l2cap/internal/scheduler_fifo_test.cc
new file mode 100644
index 0000000..ff78838
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo_test.cc
@@ -0,0 +1,107 @@
+/*
+ * 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/scheduler_fifo.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.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 {
+
+using ::testing::Return;
+
+void sync_handler(os::Handler* handler) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+  auto status = future.wait_for(std::chrono::milliseconds(300));
+  EXPECT_EQ(status, std::future_status::ready);
+}
+
+class L2capSchedulerFifoTest : public ::testing::Test {
+ 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_);
+    fifo_ = new Fifo(link_queue_.GetUpEnd(), queue_handler_);
+  }
+
+  void TearDown() override {
+    delete fifo_;
+    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<Scheduler::LowerDequeue, Scheduler::LowerEnqueue> link_queue_{10};
+  Fifo* fifo_ = nullptr;
+};
+
+TEST_F(L2capSchedulerFifoTest, send_packet) {
+  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_one_queue_{10};
+  common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_two_queue_{10};
+
+  auto mock_channel_1 = std::make_shared<testing::MockChannelImpl>();
+  EXPECT_CALL(*mock_channel_1, GetQueueDownEnd()).WillRepeatedly(Return(channel_one_queue_.GetDownEnd()));
+  EXPECT_CALL(*mock_channel_1, GetCid()).WillRepeatedly(Return(1));
+  EXPECT_CALL(*mock_channel_1, GetRemoteCid()).WillRepeatedly(Return(1));
+  auto mock_channel_2 = std::make_shared<testing::MockChannelImpl>();
+  EXPECT_CALL(*mock_channel_2, GetQueueDownEnd()).WillRepeatedly(Return(channel_two_queue_.GetDownEnd()));
+  EXPECT_CALL(*mock_channel_2, GetCid()).WillRepeatedly(Return(2));
+  EXPECT_CALL(*mock_channel_2, GetRemoteCid()).WillRepeatedly(Return(2));
+  fifo_->AttachChannel(1, mock_channel_1);
+  fifo_->AttachChannel(2, mock_channel_2);
+  os::EnqueueBuffer<Scheduler::UpperDequeue> channel_one_enqueue_buffer{channel_one_queue_.GetUpEnd()};
+  os::EnqueueBuffer<Scheduler::UpperDequeue> channel_two_enqueue_buffer{channel_two_queue_.GetUpEnd()};
+  auto packet_one = std::make_unique<packet::RawBuilder>();
+  packet_one->AddOctets({1, 2, 3});
+  auto packet_two = std::make_unique<packet::RawBuilder>();
+  packet_two->AddOctets({4, 5, 6, 7});
+  channel_one_enqueue_buffer.Enqueue(std::move(packet_one), user_handler_);
+  channel_two_enqueue_buffer.Enqueue(std::move(packet_two), user_handler_);
+  sync_handler(user_handler_);
+  sync_handler(queue_handler_);
+  sync_handler(user_handler_);
+  auto packet = link_queue_.GetDownEnd()->TryDequeue();
+  EXPECT_NE(packet, nullptr);
+  EXPECT_EQ(packet->size(), 7);
+  packet = link_queue_.GetDownEnd()->TryDequeue();
+  EXPECT_NE(packet, nullptr);
+  EXPECT_EQ(packet->size(), 8);
+  fifo_->DetachChannel(1);
+  fifo_->DetachChannel(2);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_mock.h b/gd/l2cap/internal/scheduler_mock.h
new file mode 100644
index 0000000..5fdffbe
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_mock.h
@@ -0,0 +1,39 @@
+/*
+ * 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 "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockScheduler : public Scheduler {
+ public:
+  MOCK_METHOD(void, AttachChannel, (Cid cid, std::shared_ptr<l2cap::internal::ChannelImpl> channel), (override));
+  MOCK_METHOD(void, DetachChannel, (Cid cid), (override));
+  MOCK_METHOD(void, OnPacketsReady, (Cid cid, int number_packet), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/sender.cc b/gd/l2cap/internal/sender.cc
new file mode 100644
index 0000000..7fe1dd7
--- /dev/null
+++ b/gd/l2cap/internal/sender.cc
@@ -0,0 +1,106 @@
+/*
+ * 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/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/internal/basic_mode_channel_data_controller.h"
+#include "l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/sender.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 {
+
+Sender::Sender(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel)
+    : handler_(handler), queue_end_(channel->GetQueueDownEnd()), scheduler_(scheduler), channel_id_(channel->GetCid()),
+      remote_channel_id_(channel->GetRemoteCid()),
+      data_controller_(std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_,
+                                                                 scheduler_)) {
+  try_register_dequeue();
+}
+
+Sender::~Sender() {
+  if (is_dequeue_registered_) {
+    queue_end_->UnregisterDequeue();
+  }
+}
+
+void Sender::OnPacketSent() {
+  try_register_dequeue();
+}
+
+std::unique_ptr<Sender::UpperDequeue> Sender::GetNextPacket() {
+  return data_controller_->GetNextPacket();
+}
+
+void Sender::SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option) {
+  if (mode_ == option.mode_) {
+    return;
+  }
+  if (option.mode_ == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
+    data_controller_ =
+        std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+    return;
+  }
+  if (option.mode_ == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
+    data_controller_ =
+        std::make_unique<ErtmController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+    data_controller_->SetRetransmissionAndFlowControlOptions(option);
+    return;
+  }
+}
+
+void Sender::SetFcsType(FcsType fcs_type) {
+  // TODO: FCS is enabled when "not both side explicitly disable it".
+  data_controller_->EnableFcs(fcs_type == FcsType::DEFAULT);
+}
+
+void Sender::SetIncomingMtu(Mtu mtu) {
+  // TODO: Enforce MTU
+}
+
+DataController* Sender::GetDataController() {
+  return data_controller_.get();
+}
+
+void Sender::try_register_dequeue() {
+  if (is_dequeue_registered_) {
+    return;
+  }
+  queue_end_->RegisterDequeue(handler_, common::Bind(&Sender::dequeue_callback, common::Unretained(this)));
+  is_dequeue_registered_ = true;
+}
+
+void Sender::dequeue_callback() {
+  auto packet = queue_end_->TryDequeue();
+  ASSERT(packet != nullptr);
+  data_controller_->OnSdu(std::move(packet));
+  queue_end_->UnregisterDequeue();
+  is_dequeue_registered_ = false;
+}
+
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/sender.h b/gd/l2cap/internal/sender.h
new file mode 100644
index 0000000..850a88d
--- /dev/null
+++ b/gd/l2cap/internal/sender.h
@@ -0,0 +1,85 @@
+/*
+ * 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 "data_controller.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.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 Sender {
+ public:
+  using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+  using UpperDequeue = packet::BasePacketBuilder;
+  using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+
+  Sender(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel);
+  ~Sender();
+
+  /**
+   * Callback from scheduler to indicate that scheduler already dequeued a packet from sender's queue.
+   * Segmenter can continue dequeuing from channel queue end.
+   */
+  void OnPacketSent();
+
+  /**
+   * Called by the scheduler to return the next PDU to be sent
+   */
+  std::unique_ptr<UpperDequeue> GetNextPacket();
+
+  void SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option);
+  void SetFcsType(FcsType fcs_type);
+  void SetIncomingMtu(Mtu mtu);
+
+  DataController* GetDataController();
+
+ private:
+  os::Handler* handler_;
+  UpperQueueDownEnd* queue_end_;
+  Scheduler* scheduler_;
+  const Cid channel_id_;
+  const Cid remote_channel_id_;
+  bool is_dequeue_registered_ = false;
+  RetransmissionAndFlowControlModeOption mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+  std::unique_ptr<DataController> data_controller_;
+
+  void try_register_dequeue();
+  void dequeue_callback();
+};
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/sender_test.cc b/gd/l2cap/internal/sender_test.cc
new file mode 100644
index 0000000..cb16245
--- /dev/null
+++ b/gd/l2cap/internal/sender_test.cc
@@ -0,0 +1,109 @@
+/*
+ * 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/sender.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.h"
+#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 {
+
+using ::testing::Return;
+
+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 OnPacketsReady(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<Sender::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_);
+    mock_channel_ = std::make_shared<testing::MockChannelImpl>();
+    EXPECT_CALL(*mock_channel_, GetQueueDownEnd()).WillRepeatedly(Return(channel_queue_.GetDownEnd()));
+    EXPECT_CALL(*mock_channel_, GetCid()).WillRepeatedly(Return(0x41));
+    EXPECT_CALL(*mock_channel_, GetRemoteCid()).WillRepeatedly(Return(0x41));
+    sender_ = new Sender(queue_handler_, &scheduler_, mock_channel_);
+  }
+
+  void TearDown() override {
+    delete sender_;
+    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<Sender::UpperEnqueue, Sender::UpperDequeue> channel_queue_{10};
+  std::shared_ptr<testing::MockChannelImpl> mock_channel_;
+  Sender* sender_ = 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 = sender_->GetNextPacket();
+  EXPECT_NE(packet, nullptr);
+}
+
+}  // namespace
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.cc b/gd/l2cap/l2cap_layer.cc
deleted file mode 100644
index a637998..0000000
--- a/gd/l2cap/l2cap_layer.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-#define LOG_TAG "l2cap2"
-
-#include <memory>
-
-#include "common/address.h"
-#include "common/bidi_queue.h"
-#include "hci/acl_manager.h"
-#include "hci/hci_packets.h"
-#include "l2cap/l2cap_layer.h"
-#include "module.h"
-#include "os/handler.h"
-#include "os/log.h"
-
-namespace bluetooth {
-namespace l2cap {
-
-const ModuleFactory L2capLayer::Factory = ModuleFactory([]() { return new L2capLayer(); });
-
-void L2capLayer::ListDependencies(ModuleList* list) {
-  list->add<hci::AclManager>();
-}
-
-void L2capLayer::Start() {}
-
-void L2capLayer::Stop() {}
-
-std::unique_ptr<ClassicFixedChannelManager> L2capLayer::GetClassicFixedChannelManager() {
-  return std::make_unique<ClassicFixedChannelManager>();
-}
-
-struct L2capLayer::impl {};
-
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/l2cap_packet_fuzz_test.cc b/gd/l2cap/l2cap_packet_fuzz_test.cc
new file mode 100644
index 0000000..6fecafc
--- /dev/null
+++ b/gd/l2cap/l2cap_packet_fuzz_test.cc
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#define PACKET_FUZZ_TESTING
+#include "l2cap/l2cap_packets.h"
+
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace l2cap {
+
+std::vector<void (*)(const uint8_t*, size_t)> l2cap_packet_fuzz_tests;
+
+DEFINE_AND_REGISTER_ExtendedInformationStartFrameReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_StandardInformationFrameWithFcsReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_StandardSupervisoryFrameWithFcsReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_GroupFrameReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ConfigurationRequestReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+}  // namespace l2cap
+}  // namespace bluetooth
+
+void RunL2capPacketFuzzTest(const uint8_t* data, size_t size) {
+  if (data == nullptr) return;
+  for (auto test_function : bluetooth::l2cap::l2cap_packet_fuzz_tests) {
+    test_function(data, size);
+  }
+}
\ No newline at end of file
diff --git a/gd/l2cap/l2cap_packet_test.cc b/gd/l2cap/l2cap_packet_test.cc
index 683d060..36b8791 100644
--- a/gd/l2cap/l2cap_packet_test.cc
+++ b/gd/l2cap/l2cap_packet_test.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define PACKET_TESTING
 #include "l2cap/l2cap_packets.h"
 
 #include <gtest/gtest.h>
@@ -28,139 +29,37 @@
 using bluetooth::packet::RawBuilder;
 using std::vector;
 
-namespace {
-vector<uint8_t> extended_information_start_frame = {
-    0x0B /* First size byte */,
-    0x00 /* Second size byte */,
-    0xc1 /* First ChannelId byte */,
-    0xc2,
-    0x4A /* 0x12 ReqSeq, Final, IFrame */,
-    0xD0 /* 0x13 ReqSeq */,
-    0x89 /* 0x21 TxSeq sar = START */,
-    0x8C /* 0x23 TxSeq  */,
-    0x10 /* first length byte */,
-    0x11,
-    0x01 /* first payload byte */,
-    0x02,
-    0x03,
-    0x04,
-    0x05,
-};
-}  // namespace
-
 namespace bluetooth {
 namespace l2cap {
 
-TEST(L2capPacketTest, extendedInformationStartFrameTest) {
-  uint16_t channel_id = 0xc2c1;
-  uint16_t l2cap_sdu_length = 0x1110;
-  Final f = Final::POLL_RESPONSE;
-  uint16_t req_seq = 0x1312;
-  uint16_t tx_seq = 0x2321;
-
-  std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
-  payload->AddOctets4(0x04030201);
-  payload->AddOctets1(0x05);
-
-  auto packet = ExtendedInformationStartFrameBuilder::Create(channel_id, f, req_seq, tx_seq, l2cap_sdu_length,
-                                                             std::move(payload));
-
-  ASSERT_EQ(extended_information_start_frame.size(), packet->size());
-  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter it(*packet_bytes);
-  packet->Serialize(it);
-  PacketView<true> packet_bytes_view(packet_bytes);
-  ASSERT_EQ(extended_information_start_frame.size(), packet_bytes_view.size());
-
-  BasicFrameView basic_frame_view = BasicFrameView::Create(packet_bytes_view);
-  ASSERT_TRUE(basic_frame_view.IsValid());
-  ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
-
-  StandardFrameView standard_frame_view = StandardFrameView::Create(basic_frame_view);
-  ASSERT_TRUE(standard_frame_view.IsValid());
-  ASSERT_EQ(FrameType::I_FRAME, standard_frame_view.GetFrameType());
-}
-
-vector<uint8_t> i_frame_with_fcs = {
-    0x0E, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x38, 0x61,
+std::vector<uint8_t> extended_information_start_frame = {
+    0x0B, /* First size byte */
+    0x00, /* Second size byte */
+    0xc1, /* First ChannelId byte */
+    0xc2, /**/
+    0x4A, /* 0x12 ReqSeq, Final, IFrame */
+    0xD0, /* 0x13 ReqSeq */
+    0x89, /* 0x21 TxSeq sar = START */
+    0x8C, /* 0x23 TxSeq  */
+    0x10, /* first length byte */
+    0x11, /**/
+    0x01, /* first payload byte */
+    0x02, 0x03, 0x04, 0x05,
 };
-TEST(L2capPacketTest, iFrameWithFcsTest) {
-  uint16_t channel_id = 0x0040;
-  SegmentationAndReassembly sar = SegmentationAndReassembly::UNSEGMENTED;  // 0
-  uint16_t req_seq = 0;
-  uint16_t tx_seq = 1;
-  RetransmissionDisable r = RetransmissionDisable::NORMAL;  // 0
 
-  std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
-  vector<uint8_t> payload_bytes = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
-  payload->AddOctets(payload_bytes);
+DEFINE_AND_INSTANTIATE_ExtendedInformationStartFrameReflectionTest(extended_information_start_frame);
 
-  auto packet = StandardInformationFrameWithFcsBuilder::Create(channel_id, tx_seq, r, req_seq, sar, std::move(payload));
+std::vector<uint8_t> i_frame_with_fcs = {0x0E, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02,
+                                         0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x38, 0x61};
+DEFINE_AND_INSTANTIATE_StandardInformationFrameWithFcsReflectionTest(i_frame_with_fcs);
 
-  ASSERT_EQ(i_frame_with_fcs.size(), packet->size());
-  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter it(*packet_bytes);
-  packet->Serialize(it);
-  PacketView<true> packet_bytes_view(packet_bytes);
-  ASSERT_EQ(i_frame_with_fcs.size(), packet_bytes_view.size());
+std::vector<uint8_t> rr_frame_with_fcs = {0x04, 0x00, 0x40, 0x00, 0x01, 0x01, 0xD4, 0x14};
+DEFINE_AND_INSTANTIATE_StandardSupervisoryFrameWithFcsReflectionTest(rr_frame_with_fcs);
 
-  for (size_t i = 0; i < i_frame_with_fcs.size(); i++) {
-    ASSERT_EQ(i_frame_with_fcs[i], packet_bytes_view[i]);
-  }
+std::vector<uint8_t> g_frame = {0x03, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03};
+DEFINE_AND_INSTANTIATE_GroupFrameReflectionTest(g_frame);
 
-  BasicFrameWithFcsView basic_frame_view = BasicFrameWithFcsView::Create(packet_bytes_view);
-  ASSERT_TRUE(basic_frame_view.IsValid());
-  ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
-
-  StandardFrameWithFcsView standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
-  ASSERT_TRUE(standard_frame_view.IsValid());
-  ASSERT_EQ(FrameType::I_FRAME, standard_frame_view.GetFrameType());
-
-  StandardInformationFrameWithFcsView information_frame_view =
-      StandardInformationFrameWithFcsView::Create(standard_frame_view);
-  ASSERT_TRUE(information_frame_view.IsValid());
-  ASSERT_EQ(sar, information_frame_view.GetSar());
-  ASSERT_EQ(req_seq, information_frame_view.GetReqSeq());
-  ASSERT_EQ(tx_seq, information_frame_view.GetTxSeq());
-  ASSERT_EQ(r, information_frame_view.GetR());
-}
-
-vector<uint8_t> rr_frame_with_fcs = {
-    0x04, 0x00, 0x40, 0x00, 0x01, 0x01, 0xD4, 0x14,
-};
-TEST(L2capPacketTest, rrFrameWithFcsTest) {
-  uint16_t channel_id = 0x0040;
-  SupervisoryFunction s = SupervisoryFunction::RECEIVER_READY;  // 0
-  RetransmissionDisable r = RetransmissionDisable::NORMAL;      // 0
-  uint16_t req_seq = 1;
-
-  auto packet = StandardSupervisoryFrameWithFcsBuilder::Create(channel_id, s, r, req_seq);
-
-  ASSERT_EQ(rr_frame_with_fcs.size(), packet->size());
-  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
-  BitInserter it(*packet_bytes);
-  packet->Serialize(it);
-  PacketView<true> packet_bytes_view(packet_bytes);
-  ASSERT_EQ(rr_frame_with_fcs.size(), packet_bytes_view.size());
-
-  for (size_t i = 0; i < rr_frame_with_fcs.size(); i++) {
-    ASSERT_EQ(rr_frame_with_fcs[i], packet_bytes_view[i]);
-  }
-
-  BasicFrameWithFcsView basic_frame_view = BasicFrameWithFcsView::Create(packet_bytes_view);
-  ASSERT_TRUE(basic_frame_view.IsValid());
-  ASSERT_EQ(channel_id, basic_frame_view.GetChannelId());
-
-  StandardFrameWithFcsView standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
-  ASSERT_TRUE(standard_frame_view.IsValid());
-  ASSERT_EQ(FrameType::S_FRAME, standard_frame_view.GetFrameType());
-
-  StandardSupervisoryFrameWithFcsView supervisory_frame_view =
-      StandardSupervisoryFrameWithFcsView::Create(standard_frame_view);
-  ASSERT_TRUE(supervisory_frame_view.IsValid());
-  ASSERT_EQ(s, supervisory_frame_view.GetS());
-  ASSERT_EQ(r, supervisory_frame_view.GetR());
-  ASSERT_EQ(req_seq, supervisory_frame_view.GetReqSeq());
-}
+std::vector<uint8_t> config_mtu_request = {0x04, 0x05, 0x08, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x02, 0xa0, 0x02};
+DEFINE_AND_INSTANTIATE_ConfigurationRequestReflectionTest(config_mtu_request);
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_packets.pdl b/gd/l2cap/l2cap_packets.pdl
index e940062..ae44cb1 100644
--- a/gd/l2cap/l2cap_packets.pdl
+++ b/gd/l2cap/l2cap_packets.pdl
@@ -16,6 +16,11 @@
   fcs : Fcs,
 }
 
+enum Continuation : 1 {
+  END = 0,
+  CONTINUE = 1,
+}
+
 // ChannelId 2 is connectionless
 packet GroupFrame : BasicFrame (channel_id = 0x02) {
   psm : 16,
@@ -286,19 +291,7 @@
   status : ConnectionResponseStatus,
 }
 
-enum ConfigurationContinuation : 1 {
-  END = 0,
-  CONTINUES = 1,
-}
-
-packet ConfigurationRequestBase : Control (code = CONFIGURATION_REQUEST) {
-  destination_cid : 16,
-  continuation : ConfigurationContinuation,
-  _reserved_ : 15,
-  _payload_,
-}
-
-enum ConfigurationOptionsType : 7 {
+enum ConfigurationOptionType : 7 {
   MTU = 0x01,
   FLUSH_TIMEOUT = 0x02,
   QUALITY_OF_SERVICE = 0x03,
@@ -313,18 +306,18 @@
   OPTION_IS_A_HINT = 1,
 }
 
-packet ConfigurationOptions {
-  type : ConfigurationOptionsType,
+struct ConfigurationOption {
+  type : ConfigurationOptionType,
   is_hint : ConfigurationOptionIsHint,
-  _size_(_payload_) : 8,
-  _payload_,
+  length : 8,
+  _body_,
 }
 
-packet MtuConfigurationOption : ConfigurationOptions (type = MTU) {
+struct MtuConfigurationOption : ConfigurationOption (type = MTU, length = 2) {
   mtu : 16,
 }
 
-packet FlushTimeoutConfigurationOption : ConfigurationOptions (type = FLUSH_TIMEOUT) {
+struct FlushTimeoutConfigurationOption : ConfigurationOption (type = FLUSH_TIMEOUT, length = 2) {
   flush_timeout : 16,
 }
 
@@ -334,14 +327,14 @@
   GUARANTEED = 0x02,
 }
 
-packet QualityOfServiceConfigurationOption : ConfigurationOptions (type = QUALITY_OF_SERVICE) {
+struct QualityOfServiceConfigurationOption : ConfigurationOption (type = QUALITY_OF_SERVICE, length = 22) {
   _reserved_ : 8, // Flags
   service_type : QosServiceType,
-  token_rate : 32,        // 0 = ignore, 0xffffffff = max available
+  token_rate : 32,         // 0 = ignore, 0xffffffff = max available
   token_bucket_size : 32,  // 0 = ignore, 0xffffffff = max available
-  peak_bandwidth : 32,    // Octets/second 0 = ignore
-  latency : 32,          // microseconds 0xffffffff = ignore
-  delay_variation : 32,   // microseconds 0xffffffff = ignore
+  peak_bandwidth : 32,     // Octets/second 0 = ignore
+  latency : 32,            // microseconds 0xffffffff = ignore
+  delay_variation : 32,    // microseconds 0xffffffff = ignore
 }
 
 enum RetransmissionAndFlowControlModeOption : 8 {
@@ -353,11 +346,11 @@
 }
 
 
-packet RetransmissionAndFlowControlConfigurationOption : ConfigurationOptions (type = RETRANSMISSION_AND_FLOW_CONTROL) {
+struct RetransmissionAndFlowControlConfigurationOption : ConfigurationOption (type = RETRANSMISSION_AND_FLOW_CONTROL, length = 9) {
   mode : RetransmissionAndFlowControlModeOption,
   tx_window_size : 8, // 1-32 for Flow Control and Retransmission, 1-63 for Enhanced
   max_transmit : 8,
-  retransmission_time_out : 8,
+  retransmission_time_out : 16,
   monitor_time_out : 16,
   maximum_pdu_size : 16,
 }
@@ -367,12 +360,12 @@
   DEFAULT = 1,  // 16-bit FCS
 }
 
-packet FrameCheckSequenceOption : ConfigurationOptions (type = FRAME_CHECK_SEQUENCE) {
+struct FrameCheckSequenceOption : ConfigurationOption (type = FRAME_CHECK_SEQUENCE, length = 1) {
   fcs_type : FcsType,
 }
 
 
-packet ExtendedFlowSpecificationOption : ConfigurationOptions (type = EXTENDED_FLOW_SPECIFICATION) {
+struct ExtendedFlowSpecificationOption : ConfigurationOption (type = EXTENDED_FLOW_SPECIFICATION, length = 16) {
   identifier : 8, // Default 0x01, must be 0x01 for Extended Flow-Best-Effort
   service_type : QosServiceType,
   maximum_sdu_size : 16, // Octets
@@ -381,12 +374,15 @@
   flush_timeout : 32, // in microseconds 0x0 = no retransmissions 0xFFFFFFFF = never flushed
 }
 
-packet ExtendedWindowSizeOption : ConfigurationOptions (type = EXTENDED_WINDOW_SIZE) {
+struct ExtendedWindowSizeOption : ConfigurationOption (type = EXTENDED_WINDOW_SIZE, length = 2) {
   max_window_size : 16, // 0x0000 = Valid for streaming, 0x0001-0x3FFF Valid for Enhanced Retransmission
 }
 
-packet ConfigurationRequest : ConfigurationRequestBase {
-  _payload_,
+packet ConfigurationRequest : Control (code = CONFIGURATION_REQUEST) {
+  destination_cid : 16,
+  continuation : Continuation,
+  _reserved_ : 15,
+  config : ConfigurationOption[],
 }
 
 enum ConfigurationResponseResult : 16 {
@@ -398,16 +394,12 @@
   FLOW_SPEC_REJECTED = 0x0005,
 }
 
-packet ConfigurationResponseBase : Control (code = CONFIGURATION_RESPONSE) {
+packet ConfigurationResponse : Control (code = CONFIGURATION_RESPONSE) {
   source_cid : 16,
-  continuation : ConfigurationContinuation,
+  continuation : Continuation,
   _reserved_ : 15,
   result : ConfigurationResponseResult,
-  _payload_,
-}
-
-packet ConfigurationResponse : ConfigurationResponseBase {
-  _payload_,
+  config : ConfigurationOption[],
 }
 
 packet DisconnectionRequest : Control (code = DISCONNECTION_REQUEST) {
diff --git a/gd/l2cap/le/fixed_channel.cc b/gd/l2cap/le/fixed_channel.cc
new file mode 100644
index 0000000..1e6a163
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel.cc
@@ -0,0 +1,52 @@
+/*
+ * 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/le/fixed_channel.h"
+#include "common/bind.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+hci::AddressWithType FixedChannel::GetDevice() const {
+  return impl_->GetDevice();
+}
+
+hci::Role FixedChannel::GetRole() const {
+  return impl_->GetRole();
+}
+
+void FixedChannel::RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback) {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+                                        std::move(on_close_callback)));
+}
+
+void FixedChannel::Acquire() {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Acquire, impl_));
+}
+
+void FixedChannel::Release() {
+  l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Release, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+FixedChannel::GetQueueUpEnd() const {
+  return impl_->GetQueueUpEnd();
+}
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/fixed_channel.h b/gd/l2cap/le/fixed_channel.h
new file mode 100644
index 0000000..ad4674b
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel.h
@@ -0,0 +1,95 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+namespace internal {
+class FixedChannelImpl;
+}  // namespace internal
+
+/**
+ * L2CAP fixed channel object. When a new object is created, it must be
+ * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
+ * Otherwise, {@link FixedChannel#Release()} will be called automatically.
+ *
+ */
+class FixedChannel {
+ public:
+  // Should only be constructed by modules that have access to LinkManager
+  FixedChannel(std::shared_ptr<internal::FixedChannelImpl> impl, os::Handler* l2cap_handler)
+      : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+    ASSERT(impl_ != nullptr);
+    ASSERT(l2cap_handler_ != nullptr);
+  }
+
+  hci::AddressWithType GetDevice() const;
+
+  /**
+   * Return the role we have in the associated link
+   */
+  hci::Role GetRole() const;
+
+  /**
+   * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+   * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+   * resource will be freed immediately after closing.
+   *
+   * @param user_handler The handler used to invoke the callback on
+   * @param on_close_callback The callback invoked upon channel closing.
+   */
+  using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+  void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+  /**
+   * Indicate that this Fixed Channel is being used. This will prevent ACL connection from being disconnected.
+   */
+  void Acquire();
+
+  /**
+   * Indicate that this Fixed Channel is no longer being used. ACL connection will be disconnected after
+   * kLinkIdleDisconnectTimeout if no other DynamicChannel is connected or no other Fixed Channel is  using this
+   * ACL connection. However a module can still receive data on this channel as long as it remains open.
+   */
+  void Release();
+
+  /**
+   * This method will retrieve the data channel queue to send and receive packets.
+   *
+   * {@see BidiQueueEnd}
+   *
+   * @return The upper end of a bi-directional queue.
+   */
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+  std::shared_ptr<internal::FixedChannelImpl> impl_;
+  os::Handler* l2cap_handler_;
+};
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_manager.cc b/gd/l2cap/le/fixed_channel_manager.cc
new file mode 100644
index 0000000..e36a7b4
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_manager.cc
@@ -0,0 +1,53 @@
+/*
+ * 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/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+bool FixedChannelManager::ConnectServices(hci::AddressWithType address_with_type,
+                                          OnConnectionFailureCallback on_fail_callback, os::Handler* handler) {
+  internal::LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = handler,
+      .on_fail_callback_ = std::move(on_fail_callback),
+  };
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectFixedChannelServices,
+                                              common::Unretained(link_manager_), address_with_type,
+                                              std::move(pending_fixed_channel_connection)));
+  return true;
+}
+
+bool FixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
+                                          OnRegistrationCompleteCallback on_registration_complete,
+                                          OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+  internal::FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = handler,
+      .on_registration_complete_callback_ = std::move(on_registration_complete),
+      .on_connection_open_callback_ = std::move(on_connection_open)};
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Register,
+                                              common::Unretained(service_manager_), cid,
+                                              std::move(pending_registration)));
+  return true;
+}
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_manager.h b/gd/l2cap/le/fixed_channel_manager.h
new file mode 100644
index 0000000..ea1a346
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_manager.h
@@ -0,0 +1,148 @@
+/*
+ * 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 "hci/acl_manager.h"
+#include "hci/address_with_type.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/fixed_channel.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+class L2capLeModule;
+
+namespace internal {
+class LinkManager;
+class FixedChannelServiceManagerImpl;
+}  // namespace internal
+
+class FixedChannelManager {
+ public:
+  enum class ConnectionResultCode {
+    SUCCESS = 0,
+    FAIL_NO_SERVICE_REGISTERED = 1,      // No service is registered
+    FAIL_ALL_SERVICES_HAVE_CHANNEL = 2,  // All registered services already have a channel
+    FAIL_HCI_ERROR = 3,                  // See hci_error
+  };
+
+  struct ConnectionResult {
+    ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+    hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+  };
+  /**
+   * OnConnectionFailureCallback(std::string failure_reason);
+   */
+  using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+
+  /**
+   * OnConnectionOpenCallback(FixedChannel channel);
+   */
+  using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<FixedChannel>)>;
+
+  enum class RegistrationResult {
+    SUCCESS = 0,
+    FAIL_DUPLICATE_SERVICE = 1,  // Duplicate service registration for the same CID
+    FAIL_INVALID_SERVICE = 2,    // Invalid CID
+  };
+
+  /**
+   * OnRegistrationFailureCallback(RegistrationResult result, FixedChannelService service);
+   */
+  using OnRegistrationCompleteCallback =
+      common::OnceCallback<void(RegistrationResult, std::unique_ptr<FixedChannelService>)>;
+
+  /**
+   * Connect to ALL fixed channels on a remote device
+   *
+   * - This method is asynchronous
+   * - When false is returned, the connection fails immediately
+   * - When true is returned, method caller should wait for on_fail_callback or on_open_callback registered through
+   *   RegisterService() API.
+   * - If an ACL connection does not exist, this method will create an ACL connection. As a result, on_open_callback
+   *   supplied through RegisterService() will be triggered to provide the actual FixedChannel objects
+   * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+   * - If fixed channel on a remote device is already reported as connected via on_open_callback and has been acquired
+   *   via FixedChannel#Acquire() API, it won't be reported again
+   * - If no service is registered, on_fail_callback will be triggered with FAIL_NO_SERVICE_REGISTERED
+   * - If there is an ACL connection and channels for each service is allocated, on_fail_callback will be triggered with
+   *   FAIL_ALL_SERVICES_HAVE_CHANNEL
+   *
+   * NOTE:
+   * This call will initiate an effort to connect all fixed channel services on a remote device.
+   * Due to the connectionless nature of fixed channels, all fixed channels will be connected together.
+   * If a fixed channel service does not need a particular fixed channel. It should release the received
+   * channel immediately after receiving on_open_callback via FixedChannel#Release()
+   *
+   * A module calling ConnectServices() must have called RegisterService() before.
+   * The callback will come back from on_open_callback in the service that is registered
+   *
+   * @param address_with_type: Remote device with type to make this connection.
+   * @param address_type: Address type of remote device
+   * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+   * @param handler: The handler context in which to execute the @callback parameters.
+   *
+   * Returns: true if connection was able to be initiated, false otherwise.
+   */
+  bool ConnectServices(hci::AddressWithType address_with_type, OnConnectionFailureCallback on_fail_callback,
+                       os::Handler* handler);
+
+  /**
+   * Register a service to receive incoming connections bound to a specific channel.
+   *
+   * - This method is asynchronous.
+   * - When false is returned, the registration fails immediately.
+   * - When true is returned, method caller should wait for on_service_registered callback that contains a
+   *   FixedChannelService object. The registered service can be managed from that object.
+   * - If a CID is already registered or some other error happens, on_registration_complete will be triggered with a
+   *   non-SUCCESS value
+   * - After a service is registered, any classic ACL connection will create a FixedChannel object that is
+   *   delivered through on_open_callback
+   * - on_open_callback, will only be triggered after on_service_registered callback
+   *
+   * @param cid:  cid used to receive incoming connections
+   * @param security_policy: The security policy used for the connection.
+   * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+   *        not SUCCESS, it means service is not registered due to reasons like CID already take
+   * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+   * @param handler: The handler context in which to execute the @callback parameter.
+   */
+  bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
+                       OnRegistrationCompleteCallback on_registration_complete,
+                       OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+  friend class L2capLeModule;
+
+ private:
+  // The constructor is not to be used by user code
+  FixedChannelManager(internal::FixedChannelServiceManagerImpl* service_manager, internal::LinkManager* link_manager,
+                      os::Handler* l2cap_layer_handler)
+      : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {}
+  internal::FixedChannelServiceManagerImpl* service_manager_ = nullptr;
+  internal::LinkManager* link_manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelManager);
+};
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_service.cc b/gd/l2cap/le/fixed_channel_service.cc
new file mode 100644
index 0000000..888a741
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_service.cc
@@ -0,0 +1,33 @@
+/*
+ * 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/le/fixed_channel_service.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+void FixedChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+  ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+  l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Unregister,
+                                              common::Unretained(manager_), cid_, std::move(on_unregistered),
+                                              on_unregistered_handler));
+}
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/fixed_channel_service.h b/gd/l2cap/le/fixed_channel_service.h
new file mode 100644
index 0000000..0c4556e
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_service.h
@@ -0,0 +1,59 @@
+
+/*
+ * 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 "common/callback.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+namespace internal {
+class FixedChannelServiceManagerImpl;
+}
+
+class FixedChannelService {
+ public:
+  FixedChannelService() = default;
+
+  using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+  /**
+   * Unregister a service from L2CAP module. This operation cannot fail.
+   * All channels opened for this service will be invalidated.
+   *
+   * @param on_unregistered will be triggered when unregistration is complete
+   */
+  void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+  friend internal::FixedChannelServiceManagerImpl;
+
+ private:
+  FixedChannelService(Cid cid, internal::FixedChannelServiceManagerImpl* manager, os::Handler* handler)
+      : cid_(cid), manager_(manager), l2cap_layer_handler_(handler) {}
+  Cid cid_ = kInvalidCid;
+  internal::FixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Handler* l2cap_layer_handler_;
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelService);
+};
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.cc b/gd/l2cap/le/internal/fixed_channel_impl.cc
new file mode 100644
index 0000000..9ae4e1f
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl.cc
@@ -0,0 +1,117 @@
+/*
+ * 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+hci::Role FixedChannelImpl::GetRole() const {
+  return link_->GetRole();
+}
+
+FixedChannelImpl::FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler)
+    : cid_(cid), device_(link->GetDevice()), link_(link), l2cap_handler_(l2cap_handler) {
+  ASSERT_LOG(cid_ >= kFirstFixedChannel && cid_ <= kLastFixedChannel, "Invalid cid: %d", cid_);
+  ASSERT(!device_.GetAddress().IsEmpty());
+  ASSERT(link_ != nullptr);
+  ASSERT(l2cap_handler_ != nullptr);
+}
+
+void FixedChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+                                               FixedChannel::OnCloseCallback on_close_callback) {
+  ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+  // If channel is already closed, call the callback immediately without saving it
+  if (closed_) {
+    user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+    return;
+  }
+  user_handler_ = user_handler;
+  on_close_callback_ = std::move(on_close_callback);
+}
+
+void FixedChannelImpl::OnClosed(hci::ErrorCode status) {
+  ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+             cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+  closed_ = true;
+  close_reason_ = status;
+  acquired_ = false;
+  link_ = nullptr;
+  l2cap_handler_ = nullptr;
+  if (user_handler_ == nullptr) {
+    return;
+  }
+  // On close callback can only be called once
+  user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+  user_handler_ = nullptr;
+  on_close_callback_.Reset();
+}
+
+void FixedChannelImpl::Acquire() {
+  ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+  if (closed_) {
+    LOG_WARN("%s is already closed", ToString().c_str());
+    ASSERT(!acquired_);
+    return;
+  }
+  if (acquired_) {
+    LOG_DEBUG("%s was already acquired", ToString().c_str());
+    return;
+  }
+  acquired_ = true;
+  link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::Release() {
+  ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+  if (closed_) {
+    LOG_WARN("%s is already closed", ToString().c_str());
+    ASSERT(!acquired_);
+    return;
+  }
+  if (!acquired_) {
+    LOG_DEBUG("%s was already released", ToString().c_str());
+    return;
+  }
+  acquired_ = false;
+  link_->RefreshRefCount();
+}
+
+Cid FixedChannelImpl::GetCid() const {
+  return cid_;
+}
+
+Cid FixedChannelImpl::GetRemoteCid() const {
+  return cid_;
+}
+
+void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {
+  ASSERT_LOG(false, "Should not set sender for fixed channel");
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.h b/gd/l2cap/le/internal/fixed_channel_impl.h
new file mode 100644
index 0000000..82a4125
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl.h
@@ -0,0 +1,103 @@
+/*
+ * 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 "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/le/fixed_channel.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class Link;
+
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+  FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
+
+  virtual ~FixedChannelImpl() = default;
+
+  hci::AddressWithType GetDevice() const {
+    return device_;
+  }
+
+  /* Return the role we have in the associated link */
+  virtual hci::Role GetRole() const;
+
+  virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
+
+  virtual void Acquire();
+
+  virtual void Release();
+
+  virtual bool IsAcquired() const {
+    return acquired_;
+  }
+
+  Cid GetCid() const override;
+  Cid GetRemoteCid() const override;
+  void SetSender(l2cap::internal::Sender* sender) override;
+  virtual void OnClosed(hci::ErrorCode status);
+
+  virtual std::string ToString() {
+    std::ostringstream ss;
+    ss << "Device " << device_ << " Cid 0x" << std::hex << cid_;
+    return ss.str();
+  }
+
+  common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+    return channel_queue_.GetUpEnd();
+  }
+
+  common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+    return channel_queue_.GetDownEnd();
+  }
+
+ private:
+  // Constructor states
+  // For logging purpose only
+  const Cid cid_;
+  // For logging purpose only
+  const hci::AddressWithType device_;
+  // Needed to handle Acquire() and Release()
+  Link* link_;
+  os::Handler* l2cap_handler_;
+
+  // User supported states
+  os::Handler* user_handler_ = nullptr;
+  FixedChannel::OnCloseCallback on_close_callback_{};
+
+  // Internal states
+  bool acquired_ = false;
+  bool closed_ = false;
+  hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+  static constexpr size_t kChannelQueueSize = 10;
+  common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+      kChannelQueueSize};
+
+  DISALLOW_COPY_AND_ASSIGN(FixedChannelImpl);
+};
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_impl_mock.h
new file mode 100644
index 0000000..5baa7e5
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl_mock.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "l2cap/le/internal/fixed_channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelImpl : public FixedChannelImpl {
+ public:
+  MOCK_METHOD(void, RegisterOnCloseCallback,
+              (os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
+  MOCK_METHOD(void, Acquire, (), (override));
+  MOCK_METHOD(void, Release, (), (override));
+  MOCK_METHOD(bool, IsAcquired, (), (override, const));
+  MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_impl_test.cc b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
new file mode 100644
index 0000000..9874936
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
@@ -0,0 +1,233 @@
+/*
+ * 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/le/internal/fixed_channel_impl.h"
+
+#include "common/testing/bind_test_util.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "l2cap/le/internal/link_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+using hci::Address;
+using hci::AddressWithType;
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capLeFixedChannelImplTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capLeFixedChannelImplTest, get_device) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+  EXPECT_EQ(device, fixed_channel_impl.GetDevice());
+}
+
+TEST_F(L2capLeFixedChannelImplTest, close_triggers_callback) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, register_callback_after_close_should_call_immediately) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Channel closure should do nothing
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+  // Register on close callback should trigger callback immediately
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, close_twice_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  // 2nd OnClose() callback should fail
+  EXPECT_DEATH(fixed_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, multiple_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  EXPECT_DEATH(fixed_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+                                                          common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+               ".*RegisterOnCloseCallback.*");
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, call_acquire_before_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+  EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+}
+
+TEST_F(L2capLeFixedChannelImplTest, call_release_before_registeration_should_fail) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+  EXPECT_DEATH(fixed_channel_impl.Release(), ".*Release.*");
+}
+
+TEST_F(L2capLeFixedChannelImplTest, test_acquire_release_channel) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Default should be false
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+  // Should be called 2 times after Acquire() and Release()
+  EXPECT_CALL(mock_le_link, RefreshRefCount()).Times(2);
+
+  fixed_channel_impl.Acquire();
+  EXPECT_TRUE(fixed_channel_impl.IsAcquired());
+
+  fixed_channel_impl.Release();
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, test_acquire_after_close) {
+  MockParameterProvider mock_parameter_provider;
+  MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+  AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+  EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+  FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+  // Register on close callback
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+  hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+  fixed_channel_impl.RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+  // Channel closure should trigger such callback
+  fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+  // Release or Acquire after closing should crash
+  EXPECT_CALL(mock_le_link, RefreshRefCount()).Times(0);
+  EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+  EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+
+  user_handler->Clear();
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_impl.h b/gd/l2cap/le/internal/fixed_channel_service_impl.h
new file mode 100644
index 0000000..5eed777
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_impl.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "l2cap/le/fixed_channel.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/fixed_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class FixedChannelServiceImpl {
+ public:
+  virtual ~FixedChannelServiceImpl() = default;
+
+  struct PendingRegistration {
+    os::Handler* user_handler_ = nullptr;
+    FixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+    FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+  };
+
+  virtual void NotifyChannelCreation(std::unique_ptr<FixedChannel> channel) {
+    user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+  }
+
+  friend class FixedChannelServiceManagerImpl;
+
+ protected:
+  // protected access for mocking
+  FixedChannelServiceImpl(os::Handler* user_handler,
+                          FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback)
+      : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)) {}
+
+ private:
+  os::Handler* user_handler_ = nullptr;
+  FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+};
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h
new file mode 100644
index 0000000..5a1b65d
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h
@@ -0,0 +1,40 @@
+/*
+ * 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 "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceImpl : public FixedChannelServiceImpl {
+ public:
+  MockFixedChannelServiceImpl() : FixedChannelServiceImpl(nullptr, FixedChannelManager::OnConnectionOpenCallback()) {}
+  MOCK_METHOD(void, NotifyChannelCreation, (std::unique_ptr<FixedChannel> channel), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc
new file mode 100644
index 0000000..3a2de00
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc
@@ -0,0 +1,82 @@
+/*
+ * 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/le/internal/fixed_channel_service_manager_impl.h"
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+void FixedChannelServiceManagerImpl::Register(Cid cid,
+                                              FixedChannelServiceImpl::PendingRegistration pending_registration) {
+  if (cid < kFirstFixedChannel || cid > kLastFixedChannel || cid == kLeSignallingCid) {
+    std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+  } else if (IsServiceRegistered(cid)) {
+    std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+  } else {
+    service_map_.try_emplace(cid,
+                             FixedChannelServiceImpl(pending_registration.user_handler_,
+                                                     std::move(pending_registration.on_connection_open_callback_)));
+    std::unique_ptr<FixedChannelService> user_service(new FixedChannelService(cid, this, l2cap_layer_handler_));
+    pending_registration.user_handler_->Post(
+        common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+                         FixedChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+  }
+}
+
+void FixedChannelServiceManagerImpl::Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback,
+                                                os::Handler* handler) {
+  if (IsServiceRegistered(cid)) {
+    service_map_.erase(cid);
+    handler->Post(std::move(callback));
+  } else {
+    LOG_ERROR("service not registered cid:%d", cid);
+  }
+}
+
+bool FixedChannelServiceManagerImpl::IsServiceRegistered(Cid cid) const {
+  return service_map_.find(cid) != service_map_.end();
+}
+
+FixedChannelServiceImpl* FixedChannelServiceManagerImpl::GetService(Cid cid) {
+  ASSERT(IsServiceRegistered(cid));
+  return &service_map_.find(cid)->second;
+}
+
+std::vector<std::pair<Cid, FixedChannelServiceImpl*>> FixedChannelServiceManagerImpl::GetRegisteredServices() {
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  for (auto& elem : service_map_) {
+    results.emplace_back(elem.first, &elem.second);
+  }
+  return results;
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h
new file mode 100644
index 0000000..d57c192
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h
@@ -0,0 +1,52 @@
+/*
+ * 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 "l2cap/cid.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class FixedChannelServiceManagerImpl {
+ public:
+  explicit FixedChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+      : l2cap_layer_handler_(l2cap_layer_handler) {}
+  virtual ~FixedChannelServiceManagerImpl() = default;
+
+  // All APIs must be invoked in L2CAP layer handler
+
+  virtual void Register(Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration);
+  virtual void Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+  virtual bool IsServiceRegistered(Cid cid) const;
+  virtual FixedChannelServiceImpl* GetService(Cid cid);
+  virtual std::vector<std::pair<Cid, FixedChannelServiceImpl*>> GetRegisteredServices();
+
+ private:
+  os::Handler* l2cap_layer_handler_ = nullptr;
+  std::unordered_map<Cid, FixedChannelServiceImpl> service_map_;
+};
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..068599b
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h
@@ -0,0 +1,45 @@
+/*
+ * 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 "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceManagerImpl : public FixedChannelServiceManagerImpl {
+ public:
+  MockFixedChannelServiceManagerImpl() : FixedChannelServiceManagerImpl(nullptr) {}
+  MOCK_METHOD(void, Register, (Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration), (override));
+  MOCK_METHOD(void, Unregister, (Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+              (override));
+  MOCK_METHOD(bool, IsServiceRegistered, (Cid cid), (const, override));
+  MOCK_METHOD(FixedChannelServiceImpl*, GetService, (Cid cid), (override));
+  MOCK_METHOD((std::vector<std::pair<Cid, FixedChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc b/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc
new file mode 100644
index 0000000..030933c
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 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/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class L2capLeServiceManagerTest : public ::testing::Test {
+ public:
+  ~L2capLeServiceManagerTest() override = default;
+
+  void OnServiceRegistered(bool expect_success, FixedChannelManager::RegistrationResult result,
+                           std::unique_ptr<FixedChannelService> user_service) {
+    EXPECT_EQ(result == FixedChannelManager::RegistrationResult::SUCCESS, expect_success);
+    service_registered_ = expect_success;
+  }
+
+ protected:
+  void SetUp() override {
+    manager_ = new FixedChannelServiceManagerImpl{nullptr};
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    user_handler_ = new os::Handler(thread_);
+  }
+
+  void TearDown() override {
+    user_handler_->Clear();
+    delete user_handler_;
+    delete thread_;
+    delete manager_;
+  }
+
+  void sync_user_handler() {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+  FixedChannelServiceManagerImpl* manager_ = nullptr;
+  os::Thread* thread_ = nullptr;
+  os::Handler* user_handler_ = nullptr;
+
+  bool service_registered_ = false;
+};
+
+TEST_F(L2capLeServiceManagerTest, register_and_unregister_le_fixed_channel) {
+  FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capLeServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+  Cid cid = kSmpBrCid;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_TRUE(service_registered_);
+  manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capLeServiceManagerTest, register_le_fixed_channel_bad_cid) {
+  FixedChannelServiceImpl::PendingRegistration pending_registration{
+      .user_handler_ = user_handler_,
+      .on_registration_complete_callback_ =
+          common::BindOnce(&L2capLeServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+  Cid cid = 0x1000;
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  manager_->Register(cid, std::move(pending_registration));
+  EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+  sync_user_handler();
+  EXPECT_FALSE(service_registered_);
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
new file mode 100644
index 0000000..5dc8ae4
--- /dev/null
+++ b/gd/l2cap/le/internal/link.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <chrono>
+#include <memory>
+
+#include "hci/acl_manager.h"
+#include "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "os/alarm.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class Link {
+ public:
+  Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+       std::unique_ptr<l2cap::internal::Scheduler> scheduler, l2cap::internal::ParameterProvider* parameter_provider)
+      : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)), scheduler_(std::move(scheduler)),
+        parameter_provider_(parameter_provider) {
+    ASSERT(l2cap_handler_ != nullptr);
+    ASSERT(acl_connection_ != nullptr);
+    ASSERT(scheduler_ != nullptr);
+    ASSERT(parameter_provider_ != nullptr);
+    link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+                                         parameter_provider_->GetLeLinkIdleDisconnectTimeout());
+  }
+
+  virtual ~Link() = default;
+
+  inline virtual hci::AddressWithType GetDevice() {
+    return {acl_connection_->GetAddress(), acl_connection_->GetAddressType()};
+  }
+
+  inline virtual hci::Role GetRole() {
+    return acl_connection_->GetRole();
+  }
+
+  // ACL methods
+
+  virtual void OnAclDisconnected(hci::ErrorCode status) {
+    fixed_channel_allocator_.OnAclDisconnected(status);
+  }
+
+  virtual void Disconnect() {
+    acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+  }
+
+  // FixedChannel methods
+
+  virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
+    auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
+    scheduler_->AttachChannel(cid, channel);
+    return channel;
+  }
+
+  virtual bool IsFixedChannelAllocated(Cid cid) {
+    return fixed_channel_allocator_.IsChannelAllocated(cid);
+  }
+
+  // Check how many channels are acquired or in use, if zero, start tear down timer, if non-zero, cancel tear down timer
+  virtual void RefreshRefCount() {
+    int ref_count = 0;
+    ref_count += fixed_channel_allocator_.GetRefCount();
+    ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
+    if (ref_count > 0) {
+      link_idle_disconnect_alarm_.Cancel();
+    } else {
+      link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+                                           parameter_provider_->GetLeLinkIdleDisconnectTimeout());
+    }
+  }
+
+ private:
+  os::Handler* l2cap_handler_;
+  l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
+  std::unique_ptr<hci::AclConnection> acl_connection_;
+  std::unique_ptr<l2cap::internal::Scheduler> scheduler_;
+  l2cap::internal::ParameterProvider* parameter_provider_;
+  os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
+  DISALLOW_COPY_AND_ASSIGN(Link);
+};
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager.cc b/gd/l2cap/le/internal/link_manager.cc
new file mode 100644
index 0000000..989cf3d
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager.cc
@@ -0,0 +1,152 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/internal/scheduler_fifo.h"
+#include "l2cap/le/internal/link.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/le/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+void LinkManager::ConnectFixedChannelServices(hci::AddressWithType address_with_type,
+                                              PendingFixedChannelConnection pending_fixed_channel_connection) {
+  // Check if there is any service registered
+  auto fixed_channel_services = service_manager_->GetRegisteredServices();
+  if (fixed_channel_services.empty()) {
+    // If so, return error
+    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+        std::move(pending_fixed_channel_connection.on_fail_callback_),
+        FixedChannelManager::ConnectionResult{
+            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
+    return;
+  }
+  // Otherwise, check if device has an ACL connection
+  auto* link = GetLink(address_with_type);
+  if (link != nullptr) {
+    // If device already have an ACL connection
+    // Check if all registered services have an allocated channel and allocate one if not already allocated
+    int num_new_channels = 0;
+    for (auto& fixed_channel_service : fixed_channel_services) {
+      if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
+        // This channel is already allocated for this link, do not allocated twice
+        continue;
+      }
+      // Allocate channel for newly registered fixed channels
+      auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+      fixed_channel_service.second->NotifyChannelCreation(
+          std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+      num_new_channels++;
+    }
+    // Declare connection failure if no new channels are created
+    if (num_new_channels == 0) {
+      pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+          std::move(pending_fixed_channel_connection.on_fail_callback_),
+          FixedChannelManager::ConnectionResult{
+              .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
+    }
+    // No need to create ACL connection, return without saving any pending connections
+    return;
+  }
+  // If not, create new ACL connection
+  // Add request to pending link list first
+  auto pending_link = pending_links_.find(address_with_type);
+  if (pending_link == pending_links_.end()) {
+    // Create pending link if not exist
+    pending_links_.try_emplace(address_with_type);
+    pending_link = pending_links_.find(address_with_type);
+  }
+  pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
+  // Then create new ACL connection
+  acl_manager_->CreateLeConnection(address_with_type);
+}
+
+Link* LinkManager::GetLink(hci::AddressWithType address_with_type) {
+  if (links_.find(address_with_type) == links_.end()) {
+    return nullptr;
+  }
+  return &links_.find(address_with_type)->second;
+}
+
+void LinkManager::OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
+                                     std::unique_ptr<hci::AclConnection> acl_connection) {
+  // Same link should not be connected twice
+  hci::AddressWithType connected_address_with_type(acl_connection->GetAddress(), acl_connection->GetAddressType());
+  ASSERT_LOG(GetLink(connected_address_with_type) == nullptr, "%s is connected twice without disconnection",
+             acl_connection->GetAddress().ToString().c_str());
+  auto* link_queue_up_end = acl_connection->GetAclQueueEnd();
+  // Register ACL disconnection callback in LinkManager so that we can clean up link resource properly
+  acl_connection->RegisterDisconnectCallback(
+      common::BindOnce(&LinkManager::OnDisconnect, common::Unretained(this), connected_address_with_type),
+      l2cap_handler_);
+  links_.try_emplace(connected_address_with_type, l2cap_handler_, std::move(acl_connection),
+                     std::make_unique<l2cap::internal::Fifo>(link_queue_up_end, l2cap_handler_), parameter_provider_);
+  auto* link = GetLink(connected_address_with_type);
+  // Allocate and distribute channels for all registered fixed channel services
+  auto fixed_channel_services = service_manager_->GetRegisteredServices();
+  for (auto& fixed_channel_service : fixed_channel_services) {
+    auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+    fixed_channel_service.second->NotifyChannelCreation(
+        std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+  }
+  // Remove device from pending links list, if any
+  auto pending_link = pending_links_.find(connecting_address_with_type);
+  if (pending_link == pending_links_.end()) {
+    // This an incoming connection, exit
+    return;
+  }
+  // This is an outgoing connection, remove entry in pending link list
+  pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) {
+  // Notify all pending links for this device
+  auto pending_link = pending_links_.find(address_with_type);
+  if (pending_link == pending_links_.end()) {
+    // There is no pending link, exit
+    LOG_DEBUG("Connection to %s failed without a pending link", address_with_type.ToString().c_str());
+    return;
+  }
+  for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
+    pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+        std::move(pending_fixed_channel_connection.on_fail_callback_),
+        FixedChannelManager::ConnectionResult{
+            .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
+  }
+  // Remove entry in pending link list
+  pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status) {
+  auto* link = GetLink(address_with_type);
+  ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database",
+             address_with_type.ToString().c_str(), static_cast<uint8_t>(status));
+  link->OnAclDisconnected(status);
+  links_.erase(address_with_type);
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager.h b/gd/l2cap/le/internal/link_manager.h
new file mode 100644
index 0000000..f318b83
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager.h
@@ -0,0 +1,86 @@
+/*
+ * 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 <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "os/handler.h"
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/address_with_type.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class LinkManager : public hci::LeConnectionCallbacks {
+ public:
+  LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager, FixedChannelServiceManagerImpl* service_manager,
+              l2cap::internal::ParameterProvider* parameter_provider)
+      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager), service_manager_(service_manager),
+        parameter_provider_(parameter_provider) {
+    acl_manager_->RegisterLeCallbacks(this, l2cap_handler_);
+  }
+
+  struct PendingFixedChannelConnection {
+    os::Handler* handler_;
+    FixedChannelManager::OnConnectionFailureCallback on_fail_callback_;
+  };
+
+  struct PendingLink {
+    std::vector<PendingFixedChannelConnection> pending_fixed_channel_connections_;
+  };
+
+  // ACL methods
+
+  Link* GetLink(hci::AddressWithType address_with_type);
+  void OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
+                          std::unique_ptr<hci::AclConnection> acl_connection) override;
+  void OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) override;
+  void OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status);
+
+  // FixedChannelManager methods
+
+  void ConnectFixedChannelServices(hci::AddressWithType address_with_type,
+                                   PendingFixedChannelConnection pending_fixed_channel_connection);
+
+ private:
+  // Dependencies
+  os::Handler* l2cap_handler_;
+  hci::AclManager* acl_manager_;
+  FixedChannelServiceManagerImpl* service_manager_;
+  l2cap::internal::ParameterProvider* parameter_provider_;
+
+  // Internal states
+  std::unordered_map<hci::AddressWithType, PendingLink> pending_links_;
+  std::unordered_map<hci::AddressWithType, Link> links_;
+  DISALLOW_COPY_AND_ASSIGN(LinkManager);
+};
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager_test.cc b/gd/l2cap/le/internal/link_manager_test.cc
new file mode 100644
index 0000000..59d8d6c
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager_test.cc
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2018 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/le/internal/link_manager.h"
+
+#include <future>
+#include <thread>
+
+#include "common/bind.h"
+#include "common/testing/bind_test_util.h"
+#include "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_impl_mock.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl_mock.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using hci::testing::MockAclManager;
+using l2cap::internal::testing::MockParameterProvider;
+using ::testing::_;  // Matcher to any value
+using ::testing::ByMove;
+using ::testing::DoAll;
+using testing::MockFixedChannelServiceImpl;
+using testing::MockFixedChannelServiceManagerImpl;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+constexpr static auto kTestIdleDisconnectTimeoutLong = std::chrono::milliseconds(1000);
+constexpr static auto kTestIdleDisconnectTimeoutShort = std::chrono::milliseconds(30);
+
+class L2capLeLinkManagerTest : public ::testing::Test {
+ public:
+  static void SyncHandler(os::Handler* handler) {
+    std::promise<void> promise;
+    auto future = promise.get_future();
+    handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+    future.wait_for(std::chrono::milliseconds(3));
+  }
+
+ protected:
+  void SetUp() override {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    l2cap_handler_ = new os::Handler(thread_);
+    mock_parameter_provider_ = new MockParameterProvider;
+    EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+        .WillRepeatedly(Return(kTestIdleDisconnectTimeoutLong));
+  }
+
+  void TearDown() override {
+    delete mock_parameter_provider_;
+    l2cap_handler_->Clear();
+    delete l2cap_handler_;
+    delete thread_;
+  }
+
+  os::Thread* thread_ = nullptr;
+  os::Handler* l2cap_handler_ = nullptr;
+  MockParameterProvider* mock_parameter_provider_ = nullptr;
+};
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl) {
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::RANDOM_DEVICE_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+
+  std::unique_ptr<MockAclConnection> acl_connection = std::make_unique<MockAclConnection>();
+  EXPECT_CALL(*acl_connection, RegisterDisconnectCallback(_, l2cap_handler_)).Times(1);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+  EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(hci_le_connection_callbacks), address_with_type,
+                                              std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+
+  // Step 4: Calling ConnectServices() to the same device will no trigger another connection attempt
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_2{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_2));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code,
+            FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL);
+
+  // Step 5: Register new service will cause new channels to be created during ConnectServices()
+  MockFixedChannelServiceImpl mock_service_3;
+  results.emplace_back(kSmpBrCid + 1, &mock_service_3);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_3{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  std::unique_ptr<FixedChannel> channel_3;
+  EXPECT_CALL(mock_service_3, NotifyChannelCreation(_)).WillOnce([&channel_3](std::unique_ptr<FixedChannel> channel) {
+    channel_3 = std::move(channel);
+  });
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_3));
+  EXPECT_NE(channel_3, nullptr);
+
+  user_handler->Clear();
+
+  le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::SUCCESS);
+}
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_no_service) {
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::PUBLIC_DEVICE_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Make sure no service is registered
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without any service registered will result in failure
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(0);
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_hci_failure) {
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::RANDOM_DEVICE_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+  FixedChannelManager::ConnectionResult my_result;
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::testing::BindLambdaForTesting(
+          [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection failure event should trigger connection failure callback
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).Times(0);
+  hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectFail,
+                                              common::Unretained(hci_le_connection_callbacks), address_with_type,
+                                              hci::ErrorCode::PAGE_TIMEOUT));
+  SyncHandler(hci_callback_handler);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR);
+  EXPECT_EQ(my_result.hci_error, hci::ErrorCode::PAGE_TIMEOUT);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, not_acquiring_channels_should_disconnect_acl_after_timeout) {
+  EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::RANDOM_DEVICE_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+  EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(hci_le_connection_callbacks), address_with_type,
+                                              std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  // Step 4: ave channel IDLE long enough, they will disconnect
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+  // Step 5: Link disconnect will trigger all callbacks
+  le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, acquiring_channels_should_not_disconnect_acl_after_timeout) {
+  EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::RANDOM_DEVICE_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+  EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(hci_le_connection_callbacks), address_with_type,
+                                              std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  channel_1->Acquire();
+
+  // Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+  // Step 5: Link disconnect will trigger all callbacks
+  le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, acquiring_and_releasing_channels_should_eventually_disconnect_acl) {
+  EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+      .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+  MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+  MockAclManager mock_acl_manager;
+  hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                                         hci::AddressType::PUBLIC_IDENTITY_ADDRESS);
+  auto user_handler = std::make_unique<os::Handler>(thread_);
+
+  // Step 1: Verify callback registration with HCI
+  hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+  os::Handler* hci_callback_handler = nullptr;
+  EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+  LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+                              mock_parameter_provider_);
+  EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+  EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+  // Register fake services
+  MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+  std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+  results.emplace_back(kSmpBrCid, &mock_service_1);
+  results.emplace_back(kConnectionlessCid, &mock_service_2);
+  EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+  // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+  EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+  LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+      .handler_ = user_handler.get(),
+      .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+  le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+  // Step 3: ACL connection success event should trigger channel creation for all registered services
+  auto* raw_acl_connection = new MockAclConnection();
+  std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+  EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+  EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+  std::unique_ptr<FixedChannel> channel_1, channel_2;
+  EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+    channel_1 = std::move(channel);
+  });
+  EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+    channel_2 = std::move(channel);
+  });
+  hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+                                              common::Unretained(hci_le_connection_callbacks), address_with_type,
+                                              std::move(acl_connection)));
+  SyncHandler(hci_callback_handler);
+  EXPECT_NE(channel_1, nullptr);
+  EXPECT_NE(channel_2, nullptr);
+  hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+  channel_1->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+  hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+  channel_2->RegisterOnCloseCallback(
+      user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+  channel_1->Acquire();
+
+  // Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+  // Step 5: ave channel IDLE long enough, they will disconnect
+  channel_1->Release();
+  EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+  std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+  // Step 6: Link disconnect will trigger all callbacks
+  le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+  SyncHandler(user_handler.get());
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+  EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+  user_handler->Clear();
+}
+
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_mock.h b/gd/l2cap/le/internal/link_mock.h
new file mode 100644
index 0000000..3411c95
--- /dev/null
+++ b/gd/l2cap/le/internal/link_mock.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/internal/scheduler_mock.h"
+#include "l2cap/le/internal/link.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+using hci::testing::MockAclConnection;
+
+class MockLink : public Link {
+ public:
+  explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider)
+      : Link(handler, std::make_unique<MockAclConnection>(),
+             std::make_unique<l2cap::internal::testing::MockScheduler>(), parameter_provider){};
+  MOCK_METHOD(hci::AddressWithType, GetDevice, (), (override));
+  MOCK_METHOD(hci::Role, GetRole, (), (override));
+  MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
+  MOCK_METHOD(void, Disconnect, (), (override));
+  MOCK_METHOD(std::shared_ptr<FixedChannelImpl>, AllocateFixedChannel, (Cid cid, SecurityPolicy security_policy),
+              (override));
+  MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
+  MOCK_METHOD(void, RefreshRefCount, (), (override));
+};
+
+}  // namespace testing
+}  // namespace internal
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/l2cap_le_module.cc b/gd/l2cap/le/l2cap_le_module.cc
new file mode 100644
index 0000000..781843d
--- /dev/null
+++ b/gd/l2cap/le/l2cap_le_module.cc
@@ -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.
+ */
+#define LOG_TAG "l2cap2"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/le/l2cap_le_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+const ModuleFactory L2capLeModule::Factory = ModuleFactory([]() { return new L2capLeModule(); });
+
+struct L2capLeModule::impl {
+  impl(os::Handler* l2cap_handler, hci::AclManager* acl_manager)
+      : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager) {}
+  os::Handler* l2cap_handler_;
+  hci::AclManager* acl_manager_;
+  l2cap::internal::ParameterProvider parameter_provider_;
+  internal::FixedChannelServiceManagerImpl fixed_channel_service_manager_impl_{l2cap_handler_};
+  internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
+                                      &parameter_provider_};
+};
+
+void L2capLeModule::ListDependencies(ModuleList* list) {
+  list->add<hci::AclManager>();
+}
+
+void L2capLeModule::Start() {
+  pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::AclManager>());
+}
+
+void L2capLeModule::Stop() {
+  pimpl_.reset();
+}
+
+std::string L2capLeModule::ToString() const {
+  return "L2cap Le Module";
+}
+
+std::unique_ptr<FixedChannelManager> L2capLeModule::GetFixedChannelManager() {
+  return std::unique_ptr<FixedChannelManager>(new FixedChannelManager(&pimpl_->fixed_channel_service_manager_impl_,
+                                                                      &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+}  // namespace le
+}  // namespace l2cap
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/l2cap_layer.h b/gd/l2cap/le/l2cap_le_module.h
similarity index 69%
rename from gd/l2cap/l2cap_layer.h
rename to gd/l2cap/le/l2cap_le_module.h
index 2e2aa60..3ee6acf 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/l2cap/le/l2cap_le_module.h
@@ -17,16 +17,22 @@
 
 #include <memory>
 
-#include "l2cap/classic_fixed_channel_manager.h"
+#include "l2cap/le/fixed_channel_manager.h"
 #include "module.h"
 
 namespace bluetooth {
 namespace l2cap {
+namespace le {
 
-class L2capLayer : public bluetooth::Module {
+class L2capLeModule : public bluetooth::Module {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  L2capLeModule() = default;
+  ~L2capLeModule() = default;
+
+  /**
+   * Get the api to the LE fixed channel l2cap module
+   */
+  std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
 
   static const ModuleFactory Factory;
 
@@ -37,16 +43,14 @@
 
   void Stop() override;
 
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
+  std::string ToString() const override;
 
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(L2capLeModule);
 };
 
+}  // namespace le
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/mtu.h b/gd/l2cap/mtu.h
index edaecd9..fa9bc64 100644
--- a/gd/l2cap/mtu.h
+++ b/gd/l2cap/mtu.h
@@ -20,13 +20,11 @@
 namespace bluetooth {
 namespace l2cap {
 
-using mtu_t = uint16_t;
+using Mtu = uint16_t;
 
-constexpr mtu_t kDefaultMinimumClassicMtu = 48;
-constexpr mtu_t kDefaultMinimumLeMtu = 23;
-constexpr mtu_t kMinimumClassicMtu = 48;
-constexpr mtu_t kDefaultClassicMtu = 672;
-constexpr mtu_t kMinimumLeMtu = 23;
+constexpr Mtu kMinimumClassicMtu = 48;
+constexpr Mtu kMinimumLeMtu = 23;
+constexpr Mtu kDefaultClassicMtu = 672;
 
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/l2cap/psm.h
similarity index 73%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/l2cap/psm.h
index 8a08509..0e89e62 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/l2cap/psm.h
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#pragma once
+
+#include <cstdint>
 
 namespace bluetooth {
 namespace l2cap {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+using Psm = uint16_t;
+constexpr Psm kDefaultPsm = 0;  // Invalid Psm as a default value
+
+constexpr bool IsPsmValid(Psm psm) {
+  // See Core spec 5.1 Vol 3 Part A 4.2 for definition
+  return (psm & 0x0101u) == 0x0001u;
+}
 
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/gd/l2cap/signal_id.h b/gd/l2cap/signal_id.h
index 30db90b..24372b1 100644
--- a/gd/l2cap/signal_id.h
+++ b/gd/l2cap/signal_id.h
@@ -48,6 +48,7 @@
 };
 
 constexpr SignalId kInvalidSignalId{0};
+constexpr SignalId kInitialSignalId{1};
 
 inline bool operator==(const SignalId& lhs, const SignalId& rhs) {
   return lhs.value_ == rhs.value_;
diff --git a/gd/module.cc b/gd/module.cc
index 717a825..f12da97 100644
--- a/gd/module.cc
+++ b/gd/module.cc
@@ -21,15 +21,21 @@
 
 namespace bluetooth {
 
+constexpr std::chrono::milliseconds kModuleStopTimeout = std::chrono::milliseconds(20);
+
 ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
 }
 
-Handler* Module::GetHandler() {
+std::string Module::ToString() const {
+  return "Module";
+}
+
+Handler* Module::GetHandler() const {
   ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");
   return handler_;
 }
 
-const ModuleRegistry* Module::GetModuleRegistry() {
+const ModuleRegistry* Module::GetModuleRegistry() const {
   return registry_;
 }
 
diff --git a/gd/module.h b/gd/module.h
index 96a1109..045865d 100644
--- a/gd/module.h
+++ b/gd/module.h
@@ -19,6 +19,7 @@
 #include <functional>
 #include <future>
 #include <map>
+#include <string>
 #include <vector>
 
 #include "common/bind.h"
@@ -28,8 +29,6 @@
 
 namespace bluetooth {
 
-const std::chrono::milliseconds kModuleStopTimeout = std::chrono::milliseconds(20);
-
 class Module;
 class ModuleRegistry;
 
@@ -77,9 +76,11 @@
   // Release all resources, you're about to be deleted
   virtual void Stop() = 0;
 
-  ::bluetooth::os::Handler* GetHandler();
+  virtual std::string ToString() const;
 
-  const ModuleRegistry* GetModuleRegistry();
+  ::bluetooth::os::Handler* GetHandler() const;
+
+  const ModuleRegistry* GetModuleRegistry() const;
 
   template <class T>
   T* GetDependency() const {
diff --git a/gd/neighbor/Android.bp b/gd/neighbor/Android.bp
new file mode 100644
index 0000000..bd69a3e
--- /dev/null
+++ b/gd/neighbor/Android.bp
@@ -0,0 +1,19 @@
+filegroup {
+    name: "BluetoothNeighborSources",
+    srcs: [
+            "connectability.cc",
+            "discoverability.cc",
+            "inquiry.cc",
+            "name.cc",
+            "page.cc",
+            "scan.cc",
+    ],
+}
+
+filegroup {
+    name: "BluetoothNeighborTestSources",
+    srcs: [
+            "inquiry_test.cc",
+    ],
+}
+
diff --git a/gd/neighbor/connectability.cc b/gd/neighbor/connectability.cc
new file mode 100644
index 0000000..8a60bdd
--- /dev/null
+++ b/gd/neighbor/connectability.cc
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "neighbor2"
+
+#include <memory>
+
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/connectability.h"
+#include "neighbor/scan.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ConnectabilityModule::impl {
+  void StartConnectability();
+  void StopConnectability();
+  bool IsConnectable() const;
+
+  void Start();
+  void Stop();
+
+  impl(ConnectabilityModule& connectability_module);
+
+ private:
+  ConnectabilityModule& module_;
+
+  neighbor::ScanModule* scan_module_;
+};
+
+const ModuleFactory neighbor::ConnectabilityModule::Factory =
+    ModuleFactory([]() { return new ConnectabilityModule(); });
+
+neighbor::ConnectabilityModule::impl::impl(neighbor::ConnectabilityModule& module) : module_(module) {}
+
+void neighbor::ConnectabilityModule::impl::StartConnectability() {
+  scan_module_->SetPageScan();
+}
+
+void neighbor::ConnectabilityModule::impl::StopConnectability() {
+  scan_module_->ClearPageScan();
+}
+
+bool neighbor::ConnectabilityModule::impl::IsConnectable() const {
+  return scan_module_->IsPageEnabled();
+}
+
+void neighbor::ConnectabilityModule::impl::Start() {
+  scan_module_ = module_.GetDependency<neighbor::ScanModule>();
+}
+
+void neighbor::ConnectabilityModule::impl::Stop() {}
+
+neighbor::ConnectabilityModule::ConnectabilityModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::ConnectabilityModule::~ConnectabilityModule() {
+  pimpl_.reset();
+}
+
+void neighbor::ConnectabilityModule::StartConnectability() {
+  pimpl_->StartConnectability();
+}
+
+void neighbor::ConnectabilityModule::StopConnectability() {
+  pimpl_->StopConnectability();
+}
+
+bool neighbor::ConnectabilityModule::IsConnectable() const {
+  return pimpl_->IsConnectable();
+}
+
+/**
+ * Module stuff
+ */
+void neighbor::ConnectabilityModule::ListDependencies(ModuleList* list) {
+  list->add<neighbor::ScanModule>();
+}
+
+void neighbor::ConnectabilityModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::ConnectabilityModule::Stop() {
+  pimpl_->Stop();
+}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.h b/gd/neighbor/connectability.h
similarity index 68%
copy from gd/l2cap/l2cap_layer.h
copy to gd/neighbor/connectability.h
index 2e2aa60..8cdd643 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/neighbor/connectability.h
@@ -17,36 +17,33 @@
 
 #include <memory>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace neighbor {
 
-class L2capLayer : public bluetooth::Module {
+class ConnectabilityModule : public bluetooth::Module {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  void StartConnectability();
+  void StopConnectability();
+  bool IsConnectable() const;
+
+  ConnectabilityModule();
+  ~ConnectabilityModule();
 
   static const ModuleFactory Factory;
 
  protected:
   void ListDependencies(ModuleList* list) override;
-
   void Start() override;
-
   void Stop() override;
 
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
-
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectabilityModule);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/discoverability.cc b/gd/neighbor/discoverability.cc
new file mode 100644
index 0000000..3514caf
--- /dev/null
+++ b/gd/neighbor/discoverability.cc
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/discoverability.h"
+#include "neighbor/scan.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
+static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
+
+struct DiscoverabilityModule::impl {
+  void StartDiscoverability(std::vector<hci::Lap>& laps);
+  void StopDiscoverability();
+
+  bool IsGeneralDiscoverabilityEnabled() const;
+  bool IsLimitedDiscoverabilityEnabled() const;
+
+  void Start();
+
+  impl(DiscoverabilityModule& discoverability_module);
+
+ private:
+  uint8_t num_supported_iac_;
+  std::vector<hci::Lap> laps_;
+
+  void OnCommandComplete(hci::CommandCompleteView status);
+
+  hci::HciLayer* hci_layer_;
+  neighbor::ScanModule* scan_module_;
+  os::Handler* handler_;
+
+  DiscoverabilityModule& module_;
+  void Dump() const;
+};
+
+const ModuleFactory neighbor::DiscoverabilityModule::Factory =
+    ModuleFactory([]() { return new neighbor::DiscoverabilityModule(); });
+
+neighbor::DiscoverabilityModule::impl::impl(neighbor::DiscoverabilityModule& module) : module_(module) {}
+
+void neighbor::DiscoverabilityModule::impl::OnCommandComplete(hci::CommandCompleteView status) {
+  switch (status.GetCommandOpCode()) {
+    case hci::OpCode::READ_CURRENT_IAC_LAP: {
+      auto packet = hci::ReadCurrentIacLapCompleteView::Create(status);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      laps_ = packet.GetLapsToRead();
+    } break;
+
+    case hci::OpCode::WRITE_CURRENT_IAC_LAP: {
+      auto packet = hci::WriteCurrentIacLapCompleteView::Create(status);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC: {
+      auto packet = hci::ReadNumberOfSupportedIacCompleteView::Create(status);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      num_supported_iac_ = packet.GetNumSupportIac();
+    } break;
+    default:
+      LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::DiscoverabilityModule::impl::StartDiscoverability(std::vector<hci::Lap>& laps) {
+  ASSERT(laps.size() <= num_supported_iac_);
+  hci_layer_->EnqueueCommand(hci::WriteCurrentIacLapBuilder::Create(laps),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  scan_module_->SetInquiryScan();
+}
+
+void neighbor::DiscoverabilityModule::impl::StopDiscoverability() {
+  scan_module_->ClearInquiryScan();
+}
+
+bool neighbor::DiscoverabilityModule::impl::IsGeneralDiscoverabilityEnabled() const {
+  return scan_module_->IsInquiryEnabled() && laps_.size() == 1;
+}
+
+bool neighbor::DiscoverabilityModule::impl::IsLimitedDiscoverabilityEnabled() const {
+  return scan_module_->IsInquiryEnabled() && laps_.size() == 2;
+}
+
+void neighbor::DiscoverabilityModule::impl::Start() {
+  hci_layer_ = module_.GetDependency<hci::HciLayer>();
+  scan_module_ = module_.GetDependency<neighbor::ScanModule>();
+  handler_ = module_.GetHandler();
+
+  hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadNumberOfSupportedIacBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  LOG_DEBUG("Started discoverability module");
+}
+
+void neighbor::DiscoverabilityModule::impl::Dump() const {
+  LOG_DEBUG("Number of supported iacs:%hhd", num_supported_iac_);
+  LOG_DEBUG("Number of current iacs:%zd", laps_.size());
+  for (auto it : laps_) {
+    LOG_DEBUG("  discoverability lap:%x", it.lap_);
+  }
+}
+
+neighbor::DiscoverabilityModule::DiscoverabilityModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::DiscoverabilityModule::~DiscoverabilityModule() {
+  pimpl_.reset();
+}
+
+void neighbor::DiscoverabilityModule::StartGeneralDiscoverability() {
+  std::vector<hci::Lap> laps;
+  {
+    hci::Lap lap;
+    lap.lap_ = kGeneralInquiryAccessCode;
+    laps.push_back(lap);
+  }
+  pimpl_->StartDiscoverability(laps);
+}
+
+void neighbor::DiscoverabilityModule::StartLimitedDiscoverability() {
+  std::vector<hci::Lap> laps;
+  {
+    hci::Lap lap;
+    lap.lap_ = kGeneralInquiryAccessCode;
+    laps.push_back(lap);
+  }
+
+  {
+    hci::Lap lap;
+    lap.lap_ = kLimitedInquiryAccessCode;
+    laps.push_back(lap);
+  }
+  pimpl_->StartDiscoverability(laps);
+}
+
+void neighbor::DiscoverabilityModule::StopDiscoverability() {
+  pimpl_->StopDiscoverability();
+}
+
+bool neighbor::DiscoverabilityModule::IsGeneralDiscoverabilityEnabled() const {
+  return pimpl_->IsGeneralDiscoverabilityEnabled();
+}
+
+bool neighbor::DiscoverabilityModule::IsLimitedDiscoverabilityEnabled() const {
+  return pimpl_->IsLimitedDiscoverabilityEnabled();
+}
+
+/**
+ * Module stuff
+ */
+void neighbor::DiscoverabilityModule::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+  list->add<neighbor::ScanModule>();
+}
+
+void neighbor::DiscoverabilityModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::DiscoverabilityModule::Stop() {}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.h b/gd/neighbor/discoverability.h
similarity index 66%
copy from gd/l2cap/l2cap_layer.h
copy to gd/neighbor/discoverability.h
index 2e2aa60..124716c 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/neighbor/discoverability.h
@@ -17,36 +17,36 @@
 
 #include <memory>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace neighbor {
 
-class L2capLayer : public bluetooth::Module {
+class DiscoverabilityModule : public bluetooth::Module {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  void StartGeneralDiscoverability();
+  void StartLimitedDiscoverability();
+  void StopDiscoverability();
+
+  bool IsGeneralDiscoverabilityEnabled() const;
+  bool IsLimitedDiscoverabilityEnabled() const;
 
   static const ModuleFactory Factory;
 
+  DiscoverabilityModule();
+  ~DiscoverabilityModule();
+
  protected:
   void ListDependencies(ModuleList* list) override;
-
   void Start() override;
-
   void Stop() override;
 
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
-
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscoverabilityModule);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/inquiry.cc b/gd/neighbor/inquiry.cc
new file mode 100644
index 0000000..eb94701
--- /dev/null
+++ b/gd/neighbor/inquiry.cc
@@ -0,0 +1,528 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/inquiry.h"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
+static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
+
+static inline std::string LapText(uint8_t lap) {
+  switch (lap) {
+    case kGeneralInquiryAccessCode:
+      return "General Lap";
+    case kLimitedInquiryAccessCode:
+      return "Limited Lap";
+    default:
+      return "Unknown Lap";
+  }
+}
+
+static hci::Lap general_lap_;
+static hci::Lap limited_lap_;
+
+struct InquiryModule::impl {
+  void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
+  void UnregisterCallbacks();
+
+  void StartOneShotInquiry(hci::Lap& lap, InquiryLength inquiry_length, NumResponses num_responses);
+  void StopOneShotInquiry();
+
+  void StartPeriodicInquiry(hci::Lap& lap, InquiryLength inquiry_length, NumResponses num_responses,
+                            PeriodLength max_delay, PeriodLength min_delay);
+  void StopPeriodicInquiry();
+
+  bool IsInquiryActive() const;
+  bool IsOneShotInquiryActive(hci::Lap& lap) const;
+  bool IsPeriodicInquiryActive(hci::Lap& lap) const;
+
+  void SetScanActivity(ScanParameters params);
+  ScanParameters GetScanActivity() const;
+
+  void SetScanType(hci::InquiryScanType scan_type);
+
+  void SetInquiryMode(hci::InquiryMode mode);
+
+  void Start();
+  void Stop();
+
+  bool HasCallbacks() const;
+
+  impl(InquiryModule& inquiry_module);
+
+ private:
+  InquiryCallbacks inquiry_callbacks_;
+
+  InquiryModule& module_;
+
+  hci::Lap* active_one_shot_{nullptr};
+  hci::Lap* active_periodic_{nullptr};
+
+  ScanParameters inquiry_scan_;
+  hci::InquiryMode inquiry_mode_;
+  hci::InquiryScanType inquiry_scan_type_;
+  int8_t inquiry_response_tx_power_;
+
+  void EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command);
+  void EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command);
+  void OnCommandComplete(hci::CommandCompleteView view);
+  void OnCommandStatus(hci::CommandStatusView status);
+
+  void EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command);
+  void OnCommandCompleteSync(hci::CommandCompleteView view);
+
+  void OnEvent(hci::EventPacketView view);
+
+  std::promise<void>* command_sync_{nullptr};
+
+  hci::HciLayer* hci_layer_;
+  os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::InquiryModule::Factory = ModuleFactory([]() { return new neighbor::InquiryModule(); });
+
+neighbor::InquiryModule::impl::impl(neighbor::InquiryModule& module) : module_(module) {
+  general_lap_.lap_ = kGeneralInquiryAccessCode;
+  limited_lap_.lap_ = kLimitedInquiryAccessCode;
+}
+
+void neighbor::InquiryModule::impl::OnCommandCompleteSync(hci::CommandCompleteView view) {
+  OnCommandComplete(view);
+  ASSERT(command_sync_ != nullptr);
+  command_sync_->set_value();
+}
+
+void neighbor::InquiryModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+  switch (view.GetCommandOpCode()) {
+    case hci::OpCode::INQUIRY_CANCEL: {
+      auto packet = hci::InquiryCancelCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::PERIODIC_INQUIRY_MODE: {
+      auto packet = hci::PeriodicInquiryModeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      if (active_periodic_ != nullptr) {
+        LOG_DEBUG("Periodic inquiry started lap:%s", LapText(active_periodic_->lap_).c_str());
+      }
+    } break;
+
+    case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: {
+      auto packet = hci::ExitPeriodicInquiryModeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::WRITE_INQUIRY_MODE: {
+      auto packet = hci::WriteInquiryModeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_INQUIRY_MODE: {
+      auto packet = hci::ReadInquiryModeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      inquiry_mode_ = packet.GetInquiryMode();
+    } break;
+
+    case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: {
+      auto packet = hci::ReadInquiryResponseTransmitPowerLevelCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      inquiry_response_tx_power_ = packet.GetTxPower();
+    } break;
+
+    case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: {
+      auto packet = hci::WriteInquiryScanActivityCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: {
+      auto packet = hci::ReadInquiryScanActivityCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      inquiry_scan_.interval = packet.GetInquiryScanInterval();
+      inquiry_scan_.window = packet.GetInquiryScanWindow();
+    } break;
+
+    case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: {
+      auto packet = hci::WriteInquiryScanTypeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_INQUIRY_SCAN_TYPE: {
+      auto packet = hci::ReadInquiryScanTypeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      inquiry_scan_type_ = packet.GetInquiryScanType();
+    } break;
+
+    default:
+      LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::InquiryModule::impl::OnCommandStatus(hci::CommandStatusView status) {
+  ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
+
+  switch (status.GetCommandOpCode()) {
+    case hci::OpCode::INQUIRY: {
+      auto packet = hci::InquiryStatusView::Create(status);
+      ASSERT(packet.IsValid());
+      if (active_one_shot_ != nullptr) {
+        LOG_DEBUG("Inquiry started lap:%s", LapText(active_one_shot_->lap_).c_str());
+      }
+    } break;
+
+    default:
+      LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::InquiryModule::impl::OnEvent(hci::EventPacketView view) {
+  switch (view.GetEventCode()) {
+    case hci::EventCode::INQUIRY_COMPLETE: {
+      auto packet = hci::InquiryCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      LOG_DEBUG("inquiry complete");
+      active_one_shot_ = nullptr;
+      inquiry_callbacks_.complete(packet.GetStatus());
+    } break;
+
+    case hci::EventCode::INQUIRY_RESULT: {
+      auto packet = hci::InquiryResultView::Create(view);
+      ASSERT(packet.IsValid());
+      LOG_DEBUG("Inquiry result size:%zd num_responses:%d addr:%s repetition_mode:%s cod:%s clock_offset:%d",
+                packet.size(), packet.GetNumResponses(), packet.GetBdAddr().ToString().c_str(),
+                hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+                packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset());
+      inquiry_callbacks_.result(packet);
+    } break;
+
+    case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: {
+      auto packet = hci::InquiryResultWithRssiView::Create(view);
+      ASSERT(packet.IsValid());
+      LOG_DEBUG("Inquiry result with rssi num_responses:%d addr:%s repetition_mode:%s cod:%s clock_offset:%d",
+                packet.GetNumResponses(), packet.GetAddress().ToString().c_str(),
+                hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+                packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset());
+      inquiry_callbacks_.result_with_rssi(packet);
+    } break;
+
+    case hci::EventCode::EXTENDED_INQUIRY_RESULT: {
+      auto packet = hci::ExtendedInquiryResultView::Create(view);
+      ASSERT(packet.IsValid());
+      LOG_DEBUG("Extended inquiry result addr:%s repetition_mode:%s cod:%s clock_offset:%d rssi:%hhd",
+                packet.GetAddress().ToString().c_str(),
+                hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+                packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset(), packet.GetRssi());
+      inquiry_callbacks_.extended_result(packet);
+    } break;
+
+    default:
+      LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
+      break;
+  }
+}
+
+/**
+ * impl
+ */
+void neighbor::InquiryModule::impl::RegisterCallbacks(InquiryCallbacks callbacks) {
+  inquiry_callbacks_ = callbacks;
+
+  hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT,
+                                   common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+  hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI,
+                                   common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+  hci_layer_->RegisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT,
+                                   common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+  hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_COMPLETE,
+                                   common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+}
+
+void neighbor::InquiryModule::impl::UnregisterCallbacks() {
+  hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_COMPLETE);
+  hci_layer_->UnregisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT);
+  hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI);
+  hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT);
+
+  inquiry_callbacks_ = {nullptr, nullptr, nullptr, nullptr};
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command) {
+  hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+                             handler_);
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command) {
+  hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandStatus, common::Unretained(this)),
+                             handler_);
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command) {
+  ASSERT(command_sync_ == nullptr);
+  command_sync_ = new std::promise<void>();
+  auto command_received = command_sync_->get_future();
+  hci_layer_->EnqueueCommand(std::move(command),
+                             common::BindOnce(&impl::OnCommandCompleteSync, common::Unretained(this)), handler_);
+  command_received.wait();
+  delete command_sync_;
+  command_sync_ = nullptr;
+}
+
+void neighbor::InquiryModule::impl::StartOneShotInquiry(hci::Lap& lap, InquiryLength inquiry_length,
+                                                        NumResponses num_responses) {
+  ASSERT(HasCallbacks());
+  ASSERT(active_one_shot_ == nullptr);
+  active_one_shot_ = &lap;
+  EnqueueCommandStatus(hci::InquiryBuilder::Create(lap, inquiry_length, num_responses));
+}
+
+void neighbor::InquiryModule::impl::StopOneShotInquiry() {
+  ASSERT(active_one_shot_ != nullptr);
+  active_one_shot_ = nullptr;
+  EnqueueCommandComplete(hci::InquiryCancelBuilder::Create());
+}
+
+bool neighbor::InquiryModule::impl::IsOneShotInquiryActive(hci::Lap& lap) const {
+  return active_one_shot_ == &lap;
+}
+
+void neighbor::InquiryModule::impl::StartPeriodicInquiry(hci::Lap& lap, InquiryLength inquiry_length,
+                                                         NumResponses num_responses, PeriodLength max_delay,
+                                                         PeriodLength min_delay) {
+  ASSERT(HasCallbacks());
+  ASSERT(active_periodic_ == nullptr);
+  active_periodic_ = &lap;
+  EnqueueCommandComplete(
+      hci::PeriodicInquiryModeBuilder::Create(inquiry_length, num_responses, lap, max_delay, min_delay));
+}
+
+void neighbor::InquiryModule::impl::StopPeriodicInquiry() {
+  ASSERT(active_periodic_ != nullptr);
+  active_periodic_ = nullptr;
+  EnqueueCommandComplete(hci::ExitPeriodicInquiryModeBuilder::Create());
+}
+
+bool neighbor::InquiryModule::impl::IsPeriodicInquiryActive(hci::Lap& lap) const {
+  return active_periodic_ == &lap;
+}
+
+bool neighbor::InquiryModule::impl::IsInquiryActive() const {
+  return active_one_shot_ != nullptr || active_periodic_ != nullptr;
+}
+
+void neighbor::InquiryModule::impl::Start() {
+  hci_layer_ = module_.GetDependency<hci::HciLayer>();
+  handler_ = module_.GetHandler();
+
+  EnqueueCommandComplete(hci::ReadInquiryResponseTransmitPowerLevelBuilder::Create());
+  EnqueueCommandComplete(hci::ReadInquiryScanActivityBuilder::Create());
+  EnqueueCommandComplete(hci::ReadInquiryScanTypeBuilder::Create());
+  EnqueueCommandCompleteSync(hci::ReadInquiryModeBuilder::Create());
+
+  LOG_DEBUG("Started inquiry module");
+}
+
+void neighbor::InquiryModule::impl::Stop() {
+  LOG_INFO("Inquiry scan interval:%hu window:%hu", inquiry_scan_.interval, inquiry_scan_.window);
+  LOG_INFO("Inquiry mode:%s scan_type:%s", hci::InquiryModeText(inquiry_mode_).c_str(),
+           hci::InquiryScanTypeText(inquiry_scan_type_).c_str());
+  LOG_INFO("Inquiry response tx power:%hhd", inquiry_response_tx_power_);
+  LOG_DEBUG("Stopped inquiry module");
+}
+
+void neighbor::InquiryModule::impl::SetInquiryMode(hci::InquiryMode mode) {
+  EnqueueCommandComplete(hci::WriteInquiryModeBuilder::Create(mode));
+  inquiry_mode_ = mode;
+  LOG_DEBUG("Set inquiry mode:%s", hci::InquiryModeText(mode).c_str());
+}
+
+void neighbor::InquiryModule::impl::SetScanActivity(ScanParameters params) {
+  EnqueueCommandComplete(hci::WriteInquiryScanActivityBuilder::Create(params.interval, params.window));
+  inquiry_scan_ = params;
+  LOG_DEBUG("Set scan activity interval:0x%x/%.02fms window:0x%x/%.02fms", params.interval,
+            ScanIntervalTimeMs(params.interval), params.window, ScanWindowTimeMs(params.window));
+}
+
+ScanParameters neighbor::InquiryModule::impl::GetScanActivity() const {
+  return inquiry_scan_;
+}
+
+void neighbor::InquiryModule::impl::SetScanType(hci::InquiryScanType scan_type) {
+  EnqueueCommandComplete(hci::WriteInquiryScanTypeBuilder::Create(scan_type));
+  LOG_DEBUG("Set scan type:%s", hci::InquiryScanTypeText(scan_type).c_str());
+}
+
+bool neighbor::InquiryModule::impl::HasCallbacks() const {
+  return inquiry_callbacks_.result != nullptr && inquiry_callbacks_.result_with_rssi != nullptr &&
+         inquiry_callbacks_.extended_result != nullptr && inquiry_callbacks_.complete != nullptr;
+}
+
+/**
+ * General API here
+ */
+neighbor::InquiryModule::InquiryModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::InquiryModule::~InquiryModule() {
+  pimpl_.reset();
+}
+
+void neighbor::InquiryModule::RegisterCallbacks(InquiryCallbacks callbacks) {
+  pimpl_->RegisterCallbacks(callbacks);
+}
+
+void neighbor::InquiryModule::UnregisterCallbacks() {
+  pimpl_->UnregisterCallbacks();
+}
+
+void neighbor::InquiryModule::StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
+  if (pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring start general one shot inquiry as an inquiry is already active");
+    return;
+  }
+  pimpl_->StartOneShotInquiry(general_lap_, inquiry_length, num_responses);
+  LOG_DEBUG("Started general one shot inquiry");
+}
+
+void neighbor::InquiryModule::StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
+  if (pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring start limited one shot inquiry as an inquiry is already active");
+    return;
+  }
+  pimpl_->StartOneShotInquiry(limited_lap_, inquiry_length, num_responses);
+  LOG_DEBUG("Started limited one shot inquiry");
+}
+
+void neighbor::InquiryModule::StopInquiry() {
+  if (!pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring stop one shot inquiry as an inquiry is not active");
+    return;
+  }
+  pimpl_->StopOneShotInquiry();
+  LOG_DEBUG("Stopped one shot inquiry");
+}
+
+bool neighbor::InquiryModule::IsGeneralInquiryActive() const {
+  return pimpl_->IsOneShotInquiryActive(general_lap_);
+}
+
+bool neighbor::InquiryModule::IsLimitedInquiryActive() const {
+  return pimpl_->IsOneShotInquiryActive(limited_lap_);
+}
+
+void neighbor::InquiryModule::StartGeneralPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
+                                                          PeriodLength max_delay, PeriodLength min_delay) {
+  if (pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring start general periodic inquiry as an inquiry is already active");
+    return;
+  }
+  pimpl_->StartPeriodicInquiry(general_lap_, inquiry_length, num_responses, max_delay, min_delay);
+  LOG_DEBUG("Started general periodic inquiry");
+}
+
+void neighbor::InquiryModule::StartLimitedPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
+                                                          PeriodLength max_delay, PeriodLength min_delay) {
+  if (pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring start limited periodic inquiry as an inquiry is already active");
+    return;
+  }
+  pimpl_->StartPeriodicInquiry(limited_lap_, inquiry_length, num_responses, max_delay, min_delay);
+  LOG_DEBUG("Started limited periodic inquiry");
+}
+
+void neighbor::InquiryModule::StopPeriodicInquiry() {
+  if (!pimpl_->IsInquiryActive()) {
+    LOG_WARN("Ignoring stop periodic inquiry as an inquiry is not active");
+    return;
+  }
+  pimpl_->StopPeriodicInquiry();
+  LOG_DEBUG("Stopped periodic inquiry");
+}
+
+bool neighbor::InquiryModule::IsGeneralPeriodicInquiryActive() const {
+  return pimpl_->IsPeriodicInquiryActive(general_lap_);
+}
+
+bool neighbor::InquiryModule::IsLimitedPeriodicInquiryActive() const {
+  return pimpl_->IsPeriodicInquiryActive(limited_lap_);
+}
+
+void neighbor::InquiryModule::SetScanActivity(ScanParameters params) {
+  pimpl_->SetScanActivity(params);
+}
+
+ScanParameters neighbor::InquiryModule::GetScanActivity() const {
+  return pimpl_->GetScanActivity();
+}
+
+void neighbor::InquiryModule::SetInterlacedScan() {
+  pimpl_->SetScanType(hci::InquiryScanType::INTERLACED);
+}
+
+void neighbor::InquiryModule::SetStandardScan() {
+  pimpl_->SetScanType(hci::InquiryScanType::STANDARD);
+}
+
+void neighbor::InquiryModule::SetStandardInquiryResultMode() {
+  pimpl_->SetInquiryMode(hci::InquiryMode::STANDARD);
+}
+
+void neighbor::InquiryModule::SetInquiryWithRssiResultMode() {
+  pimpl_->SetInquiryMode(hci::InquiryMode::RSSI);
+}
+
+void neighbor::InquiryModule::SetExtendedInquiryResultMode() {
+  pimpl_->SetInquiryMode(hci::InquiryMode::RSSI_OR_EXTENDED);
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::InquiryModule::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+}
+
+void neighbor::InquiryModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::InquiryModule::Stop() {
+  pimpl_->Stop();
+}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/inquiry.h b/gd/neighbor/inquiry.h
new file mode 100644
index 0000000..2da2a56
--- /dev/null
+++ b/gd/neighbor/inquiry.h
@@ -0,0 +1,90 @@
+/*
+ * 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 <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/scan_parameters.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using InquiryLength = uint8_t;  // Range: 0x01 to 0x30, 1.28 to 61.44s
+using NumResponses = uint8_t;   // Range: 0x01 to 0xff, 0x00 is unlimited
+using PeriodLength = uint16_t;  // Time = N * 1.28 s
+
+using InquiryResultCallback = std::function<void(hci::InquiryResultView view)>;
+using InquiryResultWithRssiCallback = std::function<void(hci::InquiryResultWithRssiView view)>;
+using ExtendedInquiryResultCallback = std::function<void(hci::ExtendedInquiryResultView view)>;
+using InquiryCompleteCallback = std::function<void(hci::ErrorCode status)>;
+
+using InquiryCallbacks = struct {
+  InquiryResultCallback result;
+  InquiryResultWithRssiCallback result_with_rssi;
+  ExtendedInquiryResultCallback extended_result;
+  InquiryCompleteCallback complete;
+};
+
+class InquiryModule : public bluetooth::Module {
+ public:
+  void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
+  void UnregisterCallbacks();
+
+  void StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses);
+  void StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses);
+  void StopInquiry();
+  bool IsGeneralInquiryActive() const;
+  bool IsLimitedInquiryActive() const;
+
+  void StartGeneralPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay,
+                                   PeriodLength min_delay);
+  void StartLimitedPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay,
+                                   PeriodLength min_delay);
+  void StopPeriodicInquiry();
+  bool IsGeneralPeriodicInquiryActive() const;
+  bool IsLimitedPeriodicInquiryActive() const;
+
+  void SetScanActivity(ScanParameters parms);
+  ScanParameters GetScanActivity() const;
+
+  void SetInterlacedScan();
+  void SetStandardScan();
+
+  void SetStandardInquiryResultMode();
+  void SetInquiryWithRssiResultMode();
+  void SetExtendedInquiryResultMode();
+
+  static const ModuleFactory Factory;
+
+  InquiryModule();
+  ~InquiryModule();
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+  void Start() override;
+  void Stop() override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(InquiryModule);
+};
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/inquiry_test.cc b/gd/neighbor/inquiry_test.cc
new file mode 100644
index 0000000..05d1a70
--- /dev/null
+++ b/gd/neighbor/inquiry_test.cc
@@ -0,0 +1,490 @@
+/*
+ * 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 "neighbor/inquiry.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+#include <memory>
+
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "hci/address.h"
+#include "hci/class_of_device.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace neighbor {
+namespace {
+
+static const uint8_t kNumberPacketsReadyToReceive = 1;
+
+/**
+ * This structure reflects the current state of the bluetooth chip
+ * at any given time.
+ */
+static const int8_t kInitialInquiryResponseTransmitPowerLevel = 123;
+static const uint16_t kInitialInquiryScanInterval = 1111;
+static const uint16_t kInitialInquiryScanWindow = 2222;
+
+struct HciRegister {
+  bool one_shot_inquiry_active;
+  bool periodic_inquiry_active;
+  int8_t inquiry_response_transmit_power_level;
+  uint16_t inquiry_scan_interval;
+  uint16_t inquiry_scan_window;
+  hci::InquiryScanType inquiry_scan_type;
+  hci::InquiryMode inquiry_mode;
+} hci_register_{
+    .one_shot_inquiry_active = false,
+    .periodic_inquiry_active = false,
+    .inquiry_response_transmit_power_level = kInitialInquiryResponseTransmitPowerLevel,
+    .inquiry_scan_interval = kInitialInquiryScanInterval,
+    .inquiry_scan_window = kInitialInquiryScanWindow,
+    .inquiry_scan_type = hci::InquiryScanType::STANDARD,
+    .inquiry_mode = hci::InquiryMode::STANDARD,
+};
+
+hci::PacketView<hci::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  hci::BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestHciLayer : public hci::HciLayer {
+ public:
+  void EnqueueCommand(std::unique_ptr<hci::CommandPacketBuilder> command,
+                      common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler) override {
+    GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleCommand, common::Unretained(this), std::move(command),
+                                        std::move(on_complete), common::Unretained(handler)));
+  }
+
+  void EnqueueCommand(std::unique_ptr<hci::CommandPacketBuilder> command,
+                      common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler) override {
+    GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleStatus, common::Unretained(this), std::move(command),
+                                        std::move(on_status), common::Unretained(handler)));
+  }
+
+  void HandleCommand(std::unique_ptr<hci::CommandPacketBuilder> command_builder,
+                     common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler) {
+    hci::CommandPacketView command = hci::CommandPacketView::Create(GetPacketView(std::move(command_builder)));
+    ASSERT(command.IsValid());
+
+    std::unique_ptr<packet::BasePacketBuilder> event_builder;
+    switch (command.GetOpCode()) {
+      case hci::OpCode::INQUIRY_CANCEL:
+        event_builder =
+            hci::InquiryCancelCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        hci_register_.one_shot_inquiry_active = false;
+        break;
+
+      case hci::OpCode::PERIODIC_INQUIRY_MODE:
+        event_builder =
+            hci::PeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        hci_register_.periodic_inquiry_active = true;
+        break;
+
+      case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE:
+        event_builder =
+            hci::ExitPeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        hci_register_.periodic_inquiry_active = false;
+        break;
+
+      case hci::OpCode::WRITE_INQUIRY_MODE:
+        event_builder =
+            hci::WriteInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        {
+          auto view = hci::WriteInquiryModeView::Create(hci::DiscoveryCommandView::Create(command));
+          ASSERT(view.IsValid());
+          hci_register_.inquiry_mode = view.GetInquiryMode();
+        }
+        break;
+
+      case hci::OpCode::READ_INQUIRY_MODE:
+        event_builder = hci::ReadInquiryModeCompleteBuilder::Create(
+            kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_mode);
+        break;
+
+      case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY:
+        event_builder =
+            hci::WriteInquiryScanActivityCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        {
+          auto view = hci::WriteInquiryScanActivityView::Create(hci::DiscoveryCommandView::Create(command));
+          ASSERT(view.IsValid());
+          hci_register_.inquiry_scan_interval = view.GetInquiryScanInterval();
+          hci_register_.inquiry_scan_window = view.GetInquiryScanWindow();
+        }
+        break;
+
+      case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY:
+        event_builder = hci::ReadInquiryScanActivityCompleteBuilder::Create(
+            kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_scan_interval,
+            hci_register_.inquiry_scan_window);
+        break;
+
+      case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE:
+        event_builder =
+            hci::WriteInquiryScanTypeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+        {
+          auto view = hci::WriteInquiryScanTypeView::Create(hci::DiscoveryCommandView::Create(command));
+          ASSERT(view.IsValid());
+          hci_register_.inquiry_scan_type = view.GetInquiryScanType();
+        }
+        break;
+
+      case hci::OpCode::READ_INQUIRY_SCAN_TYPE:
+        event_builder = hci::ReadInquiryScanTypeCompleteBuilder::Create(
+            kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_scan_type);
+        break;
+
+      case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL:
+        event_builder = hci::ReadInquiryResponseTransmitPowerLevelCompleteBuilder::Create(
+            kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_response_transmit_power_level);
+        break;
+
+      default:
+        LOG_INFO("Dropping unhandled command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
+        return;
+    }
+    hci::EventPacketView event = hci::EventPacketView::Create(GetPacketView(std::move(event_builder)));
+    ASSERT(event.IsValid());
+    hci::CommandCompleteView command_complete = hci::CommandCompleteView::Create(event);
+    ASSERT(command_complete.IsValid());
+    handler->Post(common::BindOnce(std::move(on_complete), std::move(command_complete)));
+
+    if (promise_sync_complete_ != nullptr) {
+      promise_sync_complete_->set_value(true);
+    }
+  }
+
+  void HandleStatus(std::unique_ptr<hci::CommandPacketBuilder> command_builder,
+                    common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler) {
+    hci::CommandPacketView command = hci::CommandPacketView::Create(GetPacketView(std::move(command_builder)));
+    ASSERT(command.IsValid());
+
+    std::unique_ptr<packet::BasePacketBuilder> event_builder;
+    switch (command.GetOpCode()) {
+      case hci::OpCode::INQUIRY:
+        event_builder = hci::InquiryStatusBuilder::Create(hci::ErrorCode::SUCCESS, kNumberPacketsReadyToReceive);
+        hci_register_.one_shot_inquiry_active = true;
+        break;
+      default:
+        LOG_INFO("Dropping unhandled status expecting command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
+        return;
+    }
+    hci::EventPacketView event = hci::EventPacketView::Create(GetPacketView(std::move(event_builder)));
+    ASSERT(event.IsValid());
+    hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
+    ASSERT(command_status.IsValid());
+    handler->Post(common::BindOnce(std::move(on_status), std::move(command_status)));
+
+    if (promise_sync_complete_ != nullptr) {
+      promise_sync_complete_->set_value(true);
+    }
+  }
+
+  void RegisterEventHandler(hci::EventCode event_code, common::Callback<void(hci::EventPacketView)> event_handler,
+                            os::Handler* handler) override {
+    switch (event_code) {
+      case hci::EventCode::INQUIRY_RESULT:
+        inquiry_result_handler_ = handler;
+        inquiry_result_callback_ = event_handler;
+        break;
+      case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
+        inquiry_result_with_rssi_handler_ = handler;
+        inquiry_result_with_rssi_callback_ = event_handler;
+        break;
+      case hci::EventCode::EXTENDED_INQUIRY_RESULT:
+        extended_inquiry_result_handler_ = handler;
+        extended_inquiry_result_callback_ = event_handler;
+        break;
+      case hci::EventCode::INQUIRY_COMPLETE:
+        inquiry_complete_handler_ = handler;
+        inquiry_complete_callback_ = event_handler;
+        break;
+      default:
+        ASSERT_TRUE(false) << "Unexpected event handler being registered";
+        break;
+    }
+  }
+
+  void UnregisterEventHandler(hci::EventCode event_code) override {
+    if (hci_register_.one_shot_inquiry_active || hci_register_.periodic_inquiry_active) {
+      LOG_ERROR("Event handlers may not be unregistered until inquiry is stopped");
+      return;
+    }
+
+    switch (event_code) {
+      case hci::EventCode::INQUIRY_RESULT:
+        inquiry_result_handler_ = nullptr;
+        inquiry_result_callback_ = {};
+        break;
+      case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
+        inquiry_result_with_rssi_handler_ = nullptr;
+        inquiry_result_with_rssi_callback_ = {};
+        break;
+      case hci::EventCode::EXTENDED_INQUIRY_RESULT:
+        extended_inquiry_result_handler_ = nullptr;
+        extended_inquiry_result_callback_ = {};
+        break;
+      case hci::EventCode::INQUIRY_COMPLETE:
+        inquiry_complete_handler_ = nullptr;
+        inquiry_complete_callback_ = {};
+        break;
+      default:
+        ASSERT_TRUE(false) << "Unexpected event handler being unregistered";
+        break;
+    }
+  }
+
+  void Synchronize(std::function<void()> func) {
+    ASSERT(promise_sync_complete_ == nullptr);
+    promise_sync_complete_ = new std::promise<bool>();
+    auto future = promise_sync_complete_->get_future();
+    func();
+    future.wait();
+    delete promise_sync_complete_;
+    promise_sync_complete_ = nullptr;
+  }
+
+  void InjectInquiryResult(std::unique_ptr<hci::InquiryResultBuilder> result) {
+    if (inquiry_result_handler_ != nullptr) {
+      hci::EventPacketView view = hci::EventPacketView::Create(GetPacketView(std::move(result)));
+      ASSERT(view.IsValid());
+      inquiry_result_handler_->Post(common::BindOnce(inquiry_result_callback_, std::move(view)));
+    }
+  }
+
+  void ListDependencies(ModuleList* list) override {}
+  void Start() override {}
+  void Stop() override {}
+
+ private:
+  std::promise<bool>* promise_sync_complete_{nullptr};
+
+  os::Handler* inquiry_result_handler_{nullptr};
+  common::Callback<void(hci::EventPacketView)> inquiry_result_callback_;
+  os::Handler* inquiry_result_with_rssi_handler_{nullptr};
+  common::Callback<void(hci::EventPacketView)> inquiry_result_with_rssi_callback_;
+  os::Handler* extended_inquiry_result_handler_{nullptr};
+  common::Callback<void(hci::EventPacketView)> extended_inquiry_result_callback_;
+  os::Handler* inquiry_complete_handler_{nullptr};
+  common::Callback<void(hci::EventPacketView)> inquiry_complete_callback_;
+};
+
+class InquiryTest : public ::testing::Test {
+ public:
+  void Result(hci::InquiryResultView view) {
+    ASSERT(view.size() >= sizeof(uint16_t));
+    promise_result_complete_->set_value(true);
+  }
+
+  void WaitForInquiryResult(std::function<void()> func) {
+    ASSERT(promise_result_complete_ == nullptr);
+    promise_result_complete_ = new std::promise<bool>();
+    auto future = promise_result_complete_->get_future();
+    func();
+    future.wait();
+    delete promise_result_complete_;
+    promise_result_complete_ = nullptr;
+  }
+
+  void ResultWithRssi(hci::InquiryResultWithRssiView view) {
+    ASSERT(view.size() >= sizeof(uint16_t));
+  }
+
+  void ExtendedResult(hci::ExtendedInquiryResultView view) {
+    ASSERT(view.size() >= sizeof(uint16_t));
+  }
+
+  void Complete(hci::ErrorCode status) {}
+
+ protected:
+  void SetUp() override {
+    test_hci_layer_ = new TestHciLayer;
+    fake_registry_.InjectTestModule(&hci::HciLayer::Factory, test_hci_layer_);
+    client_handler_ = fake_registry_.GetTestModuleHandler(&hci::HciLayer::Factory);
+    fake_registry_.Start<InquiryModule>(&thread_);
+
+    inquiry_module_ = static_cast<InquiryModule*>(fake_registry_.GetModuleUnderTest(&InquiryModule::Factory));
+
+    InquiryCallbacks inquiry_callbacks;
+    inquiry_callbacks.result = std::bind(&InquiryTest::Result, this, std::placeholders::_1);
+    inquiry_callbacks.result_with_rssi = std::bind(&InquiryTest::ResultWithRssi, this, std::placeholders::_1);
+    inquiry_callbacks.extended_result = std::bind(&InquiryTest::ExtendedResult, this, std::placeholders::_1);
+    inquiry_callbacks.complete = std::bind(&InquiryTest::Complete, this, std::placeholders::_1);
+    inquiry_module_->RegisterCallbacks(inquiry_callbacks);
+  }
+
+  void TearDown() override {
+    inquiry_module_->UnregisterCallbacks();
+    fake_registry_.StopAll();
+  }
+
+  TestModuleRegistry fake_registry_;
+  TestHciLayer* test_hci_layer_ = nullptr;
+  os::Thread& thread_ = fake_registry_.GetTestThread();
+  InquiryModule* inquiry_module_ = nullptr;
+  os::Handler* client_handler_ = nullptr;
+
+  std::promise<bool>* promise_result_complete_{nullptr};
+};
+
+TEST_F(InquiryTest, Module) {
+  ScanParameters params{
+      .interval = 0,
+      .window = 0,
+  };
+  params = inquiry_module_->GetScanActivity();
+
+  ASSERT_EQ(kInitialInquiryScanInterval, params.interval);
+  ASSERT_EQ(kInitialInquiryScanWindow, params.window);
+}
+
+TEST_F(InquiryTest, SetInquiryModes) {
+  test_hci_layer_->Synchronize([this] { inquiry_module_->SetInquiryWithRssiResultMode(); });
+  ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI);
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->SetExtendedInquiryResultMode(); });
+  ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI_OR_EXTENDED);
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->SetStandardInquiryResultMode(); });
+  ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::STANDARD);
+}
+
+TEST_F(InquiryTest, SetScanType) {
+  test_hci_layer_->Synchronize([this] { inquiry_module_->SetInterlacedScan(); });
+  ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::INTERLACED);
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->SetStandardScan(); });
+  ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::STANDARD);
+}
+
+TEST_F(InquiryTest, ScanActivity) {
+  ScanParameters params{
+      .interval = 0x1234,
+      .window = 0x5678,
+  };
+
+  test_hci_layer_->Synchronize([this, params] { inquiry_module_->SetScanActivity(params); });
+
+  ASSERT_EQ(0x1234, hci_register_.inquiry_scan_interval);
+  ASSERT_EQ(0x5678, hci_register_.inquiry_scan_window);
+
+  params = inquiry_module_->GetScanActivity();
+
+  EXPECT_EQ(0x1234, params.interval);
+  EXPECT_EQ(0x5678, params.window);
+}
+
+TEST_F(InquiryTest, OneShotGeneralInquiry) {
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralInquiry(128, 100); });
+
+  ASSERT(inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+}
+
+TEST_F(InquiryTest, OneShotLimitedInquiry) {
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StartLimitedInquiry(128, 100); });
+
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(inquiry_module_->IsLimitedInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+}
+
+TEST_F(InquiryTest, GeneralPeriodicInquiry) {
+  ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralPeriodicInquiry(128, 100, 1100, 200); });
+
+  ASSERT(inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StopPeriodicInquiry(); });
+
+  ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+}
+
+TEST_F(InquiryTest, LimitedPeriodicInquiry) {
+  ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StartLimitedPeriodicInquiry(128, 100, 1100, 200); });
+
+  ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StopPeriodicInquiry(); });
+
+  ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+}
+
+TEST_F(InquiryTest, InjectInquiryResult) {
+  ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralInquiry(128, 100); });
+
+  ASSERT(inquiry_module_->IsGeneralInquiryActive());
+  ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+  WaitForInquiryResult([this] {
+    uint8_t num_responses = 1;
+    hci::Address bd_addr;
+    hci::Address::FromString("11:22:33:44:55:66", bd_addr);
+    hci::PageScanRepetitionMode page_scan_repetition_mode = hci::PageScanRepetitionMode::R1;
+    hci::ClassOfDevice class_of_device;
+    hci::ClassOfDevice::FromString("00:00:00", class_of_device);
+    uint16_t clock_offset = 0x1234;
+    auto packet = hci::InquiryResultBuilder::Create(num_responses, bd_addr, page_scan_repetition_mode, class_of_device,
+                                                    clock_offset);
+    test_hci_layer_->InjectInquiryResult(std::move(packet));
+  });
+  test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+}
+
+}  // namespace
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/name.cc b/gd/neighbor/name.cc
new file mode 100644
index 0000000..34fa86b
--- /dev/null
+++ b/gd/neighbor/name.cc
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/name.h"
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ReadCallbackHandler {
+  ReadRemoteNameCallback callback;
+  os::Handler* handler;
+};
+
+struct CancelCallbackHandler {
+  CancelRemoteNameCallback callback;
+  os::Handler* handler;
+};
+
+constexpr std::array<uint8_t, 248> kEmptyName{};
+
+struct NameModule::impl {
+  void ReadRemoteNameRequest(hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+                             uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+                             ReadRemoteNameCallback callback, os::Handler* handler);
+  void CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback, os::Handler* handler);
+
+  void Start();
+  void Stop();
+
+  impl(const NameModule& name_module);
+
+ private:
+  const NameModule& module_;
+
+  void EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command);
+  void EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command);
+
+  void OnCommandComplete(hci::CommandCompleteView view);
+  void OnCommandStatus(hci::CommandStatusView status);
+  void OnEvent(hci::EventPacketView view);
+
+  std::unordered_map<hci::Address, std::unique_ptr<ReadCallbackHandler>> read_callback_handler_map_;
+  std::unordered_map<hci::Address, std::unique_ptr<CancelCallbackHandler>> cancel_callback_handler_map_;
+
+  hci::HciLayer* hci_layer_;
+  os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::NameModule::Factory = ModuleFactory([]() { return new neighbor::NameModule(); });
+
+neighbor::NameModule::impl::impl(const neighbor::NameModule& module) : module_(module) {}
+
+void neighbor::NameModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command) {
+  hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+                             handler_);
+}
+
+void neighbor::NameModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command) {
+  hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandStatus, common::Unretained(this)),
+                             handler_);
+}
+
+void neighbor::NameModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+  switch (view.GetCommandOpCode()) {
+    case hci::OpCode::REMOTE_NAME_REQUEST_CANCEL: {
+      auto packet = hci::RemoteNameRequestCancelCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      hci::Address address = packet.GetBdAddr();
+      ASSERT(cancel_callback_handler_map_.find(address) != cancel_callback_handler_map_.end());
+      cancel_callback_handler_map_.erase(address);
+    } break;
+    default:
+      LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::NameModule::impl::OnCommandStatus(hci::CommandStatusView status) {
+  ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
+
+  switch (status.GetCommandOpCode()) {
+    case hci::OpCode::REMOTE_NAME_REQUEST: {
+      auto packet = hci::RemoteNameRequestStatusView::Create(status);
+      ASSERT(packet.IsValid());
+    } break;
+
+    default:
+      LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::NameModule::impl::OnEvent(hci::EventPacketView view) {
+  switch (view.GetEventCode()) {
+    case hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: {
+      auto packet = hci::RemoteNameRequestCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      hci::Address address = packet.GetBdAddr();
+      ASSERT(read_callback_handler_map_.find(address) != read_callback_handler_map_.end());
+      auto read_callback_handler = std::move(read_callback_handler_map_[address]);
+      read_callback_handler->handler->Post(common::BindOnce(std::move(read_callback_handler->callback),
+                                                            packet.GetStatus(), address, packet.GetRemoteName()));
+      read_callback_handler_map_.erase(address);
+    } break;
+    default:
+      LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::NameModule::impl::Start() {
+  hci_layer_ = module_.GetDependency<hci::HciLayer>();
+  handler_ = module_.GetHandler();
+
+  hci_layer_->RegisterEventHandler(hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE,
+                                   common::Bind(&NameModule::impl::OnEvent, common::Unretained(this)), handler_);
+}
+
+void neighbor::NameModule::impl::Stop() {
+  hci_layer_->UnregisterEventHandler(hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE);
+}
+
+void neighbor::NameModule::impl::ReadRemoteNameRequest(hci::Address address,
+                                                       hci::PageScanRepetitionMode page_scan_repetition_mode,
+                                                       uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+                                                       ReadRemoteNameCallback callback, os::Handler* handler) {
+  LOG_DEBUG("%s Start read remote name request for %s", __func__, address.ToString().c_str());
+
+  if (read_callback_handler_map_.find(address) != read_callback_handler_map_.end()) {
+    LOG_WARN("Ignoring duplicate read remote name request to:%s", address.ToString().c_str());
+    handler->Post(common::BindOnce(std::move(callback), hci::ErrorCode::UNSPECIFIED_ERROR, address, kEmptyName));
+    return;
+  }
+  read_callback_handler_map_[address] = std::unique_ptr<ReadCallbackHandler>(new ReadCallbackHandler{
+      .callback = std::move(callback),
+      .handler = handler,
+  });
+
+  EnqueueCommandStatus(
+      hci::RemoteNameRequestBuilder::Create(address, page_scan_repetition_mode, clock_offset, clock_offset_valid));
+}
+
+void neighbor::NameModule::impl::CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback callback,
+                                                         os::Handler* handler) {
+  LOG_DEBUG("%s Cancel remote name request for %s", __func__, address.ToString().c_str());
+
+  if (cancel_callback_handler_map_.find(address) != cancel_callback_handler_map_.end()) {
+    LOG_WARN("Ignoring duplicate cancel remote name request to:%s", address.ToString().c_str());
+    handler->Post(common::BindOnce(std::move(callback), hci::ErrorCode::UNSPECIFIED_ERROR, address));
+    return;
+  }
+  cancel_callback_handler_map_[address] = std::unique_ptr<CancelCallbackHandler>(new CancelCallbackHandler{
+      .callback = std::move(callback),
+      .handler = handler,
+  });
+  EnqueueCommandComplete(hci::RemoteNameRequestCancelBuilder::Create(address));
+}
+
+/**
+ * General API here
+ */
+neighbor::NameModule::NameModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::NameModule::~NameModule() {
+  pimpl_.reset();
+}
+
+void neighbor::NameModule::ReadRemoteNameRequest(hci::Address address,
+                                                 hci::PageScanRepetitionMode page_scan_repetition_mode,
+                                                 uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+                                                 ReadRemoteNameCallback callback, os::Handler* handler) {
+  GetHandler()->Post(common::BindOnce(&NameModule::impl::ReadRemoteNameRequest, common::Unretained(pimpl_.get()),
+                                      address, page_scan_repetition_mode, clock_offset, clock_offset_valid,
+                                      std::move(callback), handler));
+}
+
+void neighbor::NameModule::CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback callback,
+                                                   os::Handler* handler) {
+  GetHandler()->Post(common::BindOnce(&NameModule::impl::CancelRemoteNameRequest, common::Unretained(pimpl_.get()),
+                                      address, std::move(callback), handler));
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::NameModule::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+}
+
+void neighbor::NameModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::NameModule::Stop() {
+  pimpl_->Stop();
+}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/name.h b/gd/neighbor/name.h
new file mode 100644
index 0000000..291e1de
--- /dev/null
+++ b/gd/neighbor/name.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <array>
+#include <cstdint>
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using ReadRemoteNameCallback =
+    common::OnceCallback<void(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name)>;
+using CancelRemoteNameCallback = common::OnceCallback<void(hci::ErrorCode status, hci::Address address)>;
+
+class NameModule : public bluetooth::Module {
+ public:
+  void ReadRemoteNameRequest(hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+                             uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+                             ReadRemoteNameCallback on_read_name, os::Handler* handler);
+  void CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback on_cancel, os::Handler* handler);
+
+  static const ModuleFactory Factory;
+
+  NameModule();
+  ~NameModule();
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+  void Start() override;
+  void Stop() override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(NameModule);
+};
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/page.cc b/gd/neighbor/page.cc
new file mode 100644
index 0000000..4631875
--- /dev/null
+++ b/gd/neighbor/page.cc
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/page.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct PageModule::impl {
+  void SetScanActivity(ScanParameters params);
+  ScanParameters GetScanActivity() const;
+
+  void SetScanType(hci::PageScanType type);
+
+  void SetTimeout(PageTimeout timeout);
+
+  void Start();
+  void Stop();
+
+  impl(PageModule& page_module);
+
+ private:
+  PageModule& module_;
+
+  ScanParameters scan_parameters_;
+  hci::PageScanType scan_type_;
+  PageTimeout timeout_;
+
+  void OnCommandComplete(hci::CommandCompleteView status);
+
+  hci::HciLayer* hci_layer_;
+  os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::PageModule::Factory = ModuleFactory([]() { return new neighbor::PageModule(); });
+
+neighbor::PageModule::impl::impl(neighbor::PageModule& module) : module_(module) {}
+
+void neighbor::PageModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+  switch (view.GetCommandOpCode()) {
+    case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY: {
+      auto packet = hci::WritePageScanActivityCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_PAGE_SCAN_ACTIVITY: {
+      auto packet = hci::ReadPageScanActivityCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      scan_parameters_.interval = packet.GetPageScanInterval();
+      scan_parameters_.window = packet.GetPageScanWindow();
+    } break;
+
+    case hci::OpCode::WRITE_PAGE_SCAN_TYPE: {
+      auto packet = hci::WritePageScanTypeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_PAGE_SCAN_TYPE: {
+      auto packet = hci::ReadPageScanTypeCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      scan_type_ = packet.GetPageScanType();
+    } break;
+
+    case hci::OpCode::WRITE_PAGE_TIMEOUT: {
+      auto packet = hci::WritePageTimeoutCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    case hci::OpCode::READ_PAGE_TIMEOUT: {
+      auto packet = hci::ReadPageTimeoutCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      timeout_ = packet.GetPageTimeout();
+    } break;
+
+    default:
+      LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::PageModule::impl::Start() {
+  hci_layer_ = module_.GetDependency<hci::HciLayer>();
+  handler_ = module_.GetHandler();
+
+  hci_layer_->EnqueueCommand(hci::ReadPageScanActivityBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadPageScanTypeBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadPageTimeoutBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+}
+
+void neighbor::PageModule::impl::Stop() {
+  LOG_DEBUG("Page scan interval:%hd window:%hd", scan_parameters_.interval, scan_parameters_.window);
+  LOG_DEBUG("Page scan_type:%s", hci::PageScanTypeText(scan_type_).c_str());
+}
+
+void neighbor::PageModule::impl::SetScanActivity(ScanParameters params) {
+  hci_layer_->EnqueueCommand(hci::WritePageScanActivityBuilder::Create(params.interval, params.window),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadPageScanActivityBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  LOG_DEBUG("Set page scan activity interval:0x%x/%.02fms window:0x%x/%.02fms", params.interval,
+            ScanIntervalTimeMs(params.interval), params.window, ScanWindowTimeMs(params.window));
+}
+
+ScanParameters neighbor::PageModule::impl::GetScanActivity() const {
+  return scan_parameters_;
+}
+
+void neighbor::PageModule::impl::SetScanType(hci::PageScanType scan_type) {
+  hci_layer_->EnqueueCommand(hci::WritePageScanTypeBuilder::Create(scan_type),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadPageScanTypeBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  LOG_DEBUG("Set page scan type:%s", hci::PageScanTypeText(scan_type).c_str());
+}
+
+void neighbor::PageModule::impl::SetTimeout(PageTimeout timeout) {
+  hci_layer_->EnqueueCommand(hci::WritePageTimeoutBuilder::Create(timeout),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+  hci_layer_->EnqueueCommand(hci::ReadPageTimeoutBuilder::Create(),
+                             common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+  LOG_DEBUG("Set page scan timeout:0x%x/%.02fms", timeout, PageTimeoutMs(timeout));
+}
+
+/**
+ * General API here
+ */
+neighbor::PageModule::PageModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::PageModule::~PageModule() {
+  pimpl_.reset();
+}
+
+void neighbor::PageModule::SetScanActivity(ScanParameters params) {
+  pimpl_->SetScanActivity(params);
+}
+
+ScanParameters neighbor::PageModule::GetScanActivity() const {
+  return pimpl_->GetScanActivity();
+}
+
+void neighbor::PageModule::SetInterlacedScan() {
+  pimpl_->SetScanType(hci::PageScanType::INTERLACED);
+}
+
+void neighbor::PageModule::SetStandardScan() {
+  pimpl_->SetScanType(hci::PageScanType::STANDARD);
+}
+
+void neighbor::PageModule::SetTimeout(PageTimeout timeout) {
+  pimpl_->SetTimeout(timeout);
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::PageModule::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+}
+
+void neighbor::PageModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::PageModule::Stop() {
+  pimpl_->Stop();
+}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/page.h b/gd/neighbor/page.h
new file mode 100644
index 0000000..075217b
--- /dev/null
+++ b/gd/neighbor/page.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/scan_parameters.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using PageTimeout = uint16_t;  // Range = 0x0001 to 0xffff, Time N * 0.625ms
+
+inline double PageTimeoutMs(PageTimeout timeout) {
+  return kTimeTickMs * timeout;
+}
+
+class PageModule : public bluetooth::Module {
+ public:
+  void SetScanActivity(ScanParameters params);
+  ScanParameters GetScanActivity() const;
+
+  void SetInterlacedScan();
+  void SetStandardScan();
+
+  void SetTimeout(PageTimeout timeout);
+
+  static const ModuleFactory Factory;
+
+  PageModule();
+  ~PageModule();
+
+ protected:
+  void ListDependencies(ModuleList* list) override;
+  void Start() override;
+  void Stop() override;
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(PageModule);
+};
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/scan.cc b/gd/neighbor/scan.cc
new file mode 100644
index 0000000..5232b08
--- /dev/null
+++ b/gd/neighbor/scan.cc
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/scan.h"
+#include <memory>
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ScanModule::impl {
+  impl(ScanModule& module);
+
+  void SetInquiryScan(bool enabled);
+  bool IsInquiryEnabled() const;
+
+  void SetPageScan(bool enabled);
+  bool IsPageEnabled() const;
+
+  void Start();
+  void Stop();
+
+ private:
+  ScanModule& module_;
+
+  bool inquiry_scan_enabled_;
+  bool page_scan_enabled_;
+
+  void WriteScanEnable();
+  void ReadScanEnable(hci::ScanEnable);
+
+  void OnCommandComplete(hci::CommandCompleteView status);
+
+  hci::HciLayer* hci_layer_;
+  os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::ScanModule::Factory = ModuleFactory([]() { return new neighbor::ScanModule(); });
+
+neighbor::ScanModule::impl::impl(neighbor::ScanModule& module)
+    : module_(module), inquiry_scan_enabled_(false), page_scan_enabled_(false) {}
+
+void neighbor::ScanModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+  switch (view.GetCommandOpCode()) {
+    case hci::OpCode::READ_SCAN_ENABLE: {
+      auto packet = hci::ReadScanEnableCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+      ReadScanEnable(packet.GetScanEnable());
+    } break;
+
+    case hci::OpCode::WRITE_SCAN_ENABLE: {
+      auto packet = hci::WriteScanEnableCompleteView::Create(view);
+      ASSERT(packet.IsValid());
+      ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+    } break;
+
+    default:
+      LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+      break;
+  }
+}
+
+void neighbor::ScanModule::impl::WriteScanEnable() {
+  hci::ScanEnable scan_enable;
+
+  if (inquiry_scan_enabled_ && !page_scan_enabled_) {
+    scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
+  } else if (!inquiry_scan_enabled_ && page_scan_enabled_) {
+    scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
+  } else if (inquiry_scan_enabled_ && page_scan_enabled_) {
+    scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
+  } else {
+    scan_enable = hci::ScanEnable::NO_SCANS;
+  }
+
+  {
+    std::unique_ptr<hci::WriteScanEnableBuilder> packet = hci::WriteScanEnableBuilder::Create(scan_enable);
+    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+                               handler_);
+  }
+
+  {
+    std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
+    hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+                               handler_);
+  }
+}
+
+void neighbor::ScanModule::impl::ReadScanEnable(hci::ScanEnable scan_enable) {
+  switch (scan_enable) {
+    case hci::ScanEnable::INQUIRY_SCAN_ONLY:
+      inquiry_scan_enabled_ = true;
+      page_scan_enabled_ = false;
+      break;
+
+    case hci::ScanEnable::PAGE_SCAN_ONLY:
+      inquiry_scan_enabled_ = false;
+      page_scan_enabled_ = true;
+      break;
+
+    case hci::ScanEnable::INQUIRY_AND_PAGE_SCAN:
+      inquiry_scan_enabled_ = true;
+      page_scan_enabled_ = true;
+      break;
+
+    default:
+      inquiry_scan_enabled_ = false;
+      page_scan_enabled_ = false;
+      break;
+  }
+}
+
+void neighbor::ScanModule::impl::SetInquiryScan(bool enabled) {
+  inquiry_scan_enabled_ = enabled;
+  WriteScanEnable();
+}
+
+void neighbor::ScanModule::impl::SetPageScan(bool enabled) {
+  page_scan_enabled_ = enabled;
+  WriteScanEnable();
+}
+
+bool neighbor::ScanModule::impl::IsInquiryEnabled() const {
+  return inquiry_scan_enabled_;
+}
+
+bool neighbor::ScanModule::impl::IsPageEnabled() const {
+  return page_scan_enabled_;
+}
+
+void neighbor::ScanModule::impl::Start() {
+  hci_layer_ = module_.GetDependency<hci::HciLayer>();
+  handler_ = module_.GetHandler();
+
+  std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
+  hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+                             handler_);
+}
+
+void neighbor::ScanModule::impl::Stop() {
+  LOG_DEBUG("inquiry scan enabled:%d page scan enabled:%d", inquiry_scan_enabled_, page_scan_enabled_);
+}
+
+neighbor::ScanModule::ScanModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::ScanModule::~ScanModule() {
+  pimpl_.reset();
+}
+
+void neighbor::ScanModule::SetInquiryScan() {
+  pimpl_->SetInquiryScan(true);
+}
+
+void neighbor::ScanModule::ClearInquiryScan() {
+  pimpl_->SetInquiryScan(false);
+}
+
+void neighbor::ScanModule::SetPageScan() {
+  pimpl_->SetPageScan(true);
+}
+
+void neighbor::ScanModule::ClearPageScan() {
+  pimpl_->SetPageScan(false);
+}
+
+bool neighbor::ScanModule::IsInquiryEnabled() const {
+  return pimpl_->IsInquiryEnabled();
+}
+
+bool neighbor::ScanModule::IsPageEnabled() const {
+  return pimpl_->IsPageEnabled();
+}
+
+void neighbor::ScanModule::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+}
+
+void neighbor::ScanModule::Start() {
+  pimpl_->Start();
+}
+
+void neighbor::ScanModule::Stop() {
+  pimpl_->Stop();
+}
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.h b/gd/neighbor/scan.h
similarity index 68%
copy from gd/l2cap/l2cap_layer.h
copy to gd/neighbor/scan.h
index 2e2aa60..b6499d3 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/neighbor/scan.h
@@ -17,36 +17,37 @@
 
 #include <memory>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace neighbor {
 
-class L2capLayer : public bluetooth::Module {
+class ScanModule : public bluetooth::Module {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  ScanModule();
+  ~ScanModule();
+
+  void SetInquiryScan();
+  void ClearInquiryScan();
+  bool IsInquiryEnabled() const;
+
+  void SetPageScan();
+  void ClearPageScan();
+  bool IsPageEnabled() const;
 
   static const ModuleFactory Factory;
 
  protected:
   void ListDependencies(ModuleList* list) override;
-
   void Start() override;
-
   void Stop() override;
 
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
-
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScanModule);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/neighbor/scan_parameters.h b/gd/neighbor/scan_parameters.h
new file mode 100644
index 0000000..8927ee1
--- /dev/null
+++ b/gd/neighbor/scan_parameters.h
@@ -0,0 +1,42 @@
+/*
+ * 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 <cstdint>
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr double kTimeTickMs = 0.625;
+
+using ScanInterval = uint16_t;  // Range 0x0012 to 0x1000; only even values valid  11.25 to 2560ms
+using ScanWindow = uint16_t;    // Range 0x0011 to 0x1000;  10.625ms to 2560ms
+
+inline double ScanIntervalTimeMs(ScanInterval interval) {
+  return kTimeTickMs * interval;
+}
+
+inline double ScanWindowTimeMs(ScanWindow window) {
+  return kTimeTickMs * window;
+}
+
+using ScanParameters = struct {
+  ScanInterval interval;
+  ScanWindow window;
+};
+
+}  // namespace neighbor
+}  // namespace bluetooth
diff --git a/gd/os/linux_generic/reactive_semaphore.cc b/gd/os/linux_generic/reactive_semaphore.cc
index 4cc0b4c..df0050a 100644
--- a/gd/os/linux_generic/reactive_semaphore.cc
+++ b/gd/os/linux_generic/reactive_semaphore.cc
@@ -16,6 +16,7 @@
 
 #include "reactive_semaphore.h"
 
+#include <error.h>
 #include <sys/eventfd.h>
 #include <unistd.h>
 #include <functional>
@@ -33,19 +34,19 @@
 ReactiveSemaphore::~ReactiveSemaphore() {
   int close_status;
   RUN_NO_INTR(close_status = close(fd_));
-  ASSERT(close_status != -1);
+  ASSERT_LOG(close_status != -1, "close failed: %s", strerror(errno));
 }
 
 void ReactiveSemaphore::Decrease() {
   uint64_t val = 0;
   auto read_result = eventfd_read(fd_, &val);
-  ASSERT(read_result != -1);
+  ASSERT_LOG(read_result != -1, "decrease failed: %s", strerror(errno));
 }
 
 void ReactiveSemaphore::Increase() {
   uint64_t val = 1;
   auto write_result = eventfd_write(fd_, val);
-  ASSERT(write_result != -1);
+  ASSERT_LOG(write_result != -1, "increase failed: %s", strerror(errno));
 }
 
 int ReactiveSemaphore::GetFd() {
diff --git a/gd/os/linux_generic/reactor.cc b/gd/os/linux_generic/reactor.cc
index 24a677a..220d3a9 100644
--- a/gd/os/linux_generic/reactor.cc
+++ b/gd/os/linux_generic/reactor.cc
@@ -152,7 +152,7 @@
   auto* reactable = new Reactable(fd, on_read_ready, on_write_ready);
   epoll_event event = {
       .events = poll_event_type,
-      {.ptr = reactable}
+      .data = {.ptr = reactable},
   };
   int register_fd;
   RUN_NO_INTR(register_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event));
@@ -217,7 +217,7 @@
   }
   epoll_event event = {
       .events = poll_event_type,
-      {.ptr = reactable}
+      .data = {.ptr = reactable},
   };
   int modify_fd;
   RUN_NO_INTR(modify_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, reactable->fd_, &event));
diff --git a/gd/packet/Android.bp b/gd/packet/Android.bp
index c65cf8c..c9ddb7a 100644
--- a/gd/packet/Android.bp
+++ b/gd/packet/Android.bp
@@ -5,6 +5,7 @@
         "byte_inserter.cc",
         "byte_observer.cc",
         "iterator.cc",
+        "fragmenting_inserter.cc",
         "packet_view.cc",
         "raw_builder.cc",
         "view.cc",
@@ -15,6 +16,7 @@
     name: "BluetoothPacketTestSources",
     srcs: [
         "bit_inserter_unittest.cc",
+        "fragmenting_inserter_unittest.cc",
         "packet_builder_unittest.cc",
         "packet_view_unittest.cc",
         "raw_builder_unittest.cc",
diff --git a/gd/packet/bit_inserter.cc b/gd/packet/bit_inserter.cc
index 0180cd8..0a8f2bc 100644
--- a/gd/packet/bit_inserter.cc
+++ b/gd/packet/bit_inserter.cc
@@ -29,15 +29,14 @@
 
 void BitInserter::insert_bits(uint8_t byte, size_t num_bits) {
   size_t total_bits = num_bits + num_saved_bits_;
-  uint16_t new_value = saved_bits_ | (static_cast<uint16_t>(byte) << num_saved_bits_);
+  uint16_t new_value = static_cast<uint8_t>(saved_bits_) | (static_cast<uint16_t>(byte) << num_saved_bits_);
   if (total_bits >= 8) {
-    uint8_t new_byte = static_cast<uint8_t>(new_value);
-    ByteInserter::insert_byte(new_byte);
+    ByteInserter::insert_byte(static_cast<uint8_t>(new_value));
     total_bits -= 8;
     new_value = new_value >> 8;
   }
   num_saved_bits_ = total_bits;
-  uint8_t mask = 0xff >> (8 - num_saved_bits_);
+  uint8_t mask = static_cast<uint8_t>(0xff) >> (8 - num_saved_bits_);
   saved_bits_ = static_cast<uint8_t>(new_value) & mask;
 }
 
@@ -45,9 +44,5 @@
   insert_bits(byte, 8);
 }
 
-bool BitInserter::IsByteAligned() {
-  return num_saved_bits_ == 0;
-}
-
 }  // namespace packet
 }  // namespace bluetooth
diff --git a/gd/packet/bit_inserter.h b/gd/packet/bit_inserter.h
index 2aa1ad6..487eba5 100644
--- a/gd/packet/bit_inserter.h
+++ b/gd/packet/bit_inserter.h
@@ -29,15 +29,13 @@
 class BitInserter : public ByteInserter {
  public:
   BitInserter(std::vector<uint8_t>& vector);
-  virtual ~BitInserter();
+  ~BitInserter() override;
 
-  void insert_bits(uint8_t byte, size_t num_bits);
+  virtual void insert_bits(uint8_t byte, size_t num_bits);
 
-  void insert_byte(uint8_t byte);
+  void insert_byte(uint8_t byte) override;
 
-  bool IsByteAligned();
-
- private:
+ protected:
   size_t num_saved_bits_{0};
   uint8_t saved_bits_{0};
 };
diff --git a/gd/packet/byte_inserter.cc b/gd/packet/byte_inserter.cc
index f7fc9c0..b872427 100644
--- a/gd/packet/byte_inserter.cc
+++ b/gd/packet/byte_inserter.cc
@@ -24,10 +24,10 @@
 ByteInserter::ByteInserter(std::vector<uint8_t>& vector) : std::back_insert_iterator<std::vector<uint8_t>>(vector) {}
 
 ByteInserter::~ByteInserter() {
-  ASSERT(registered_observers_.size() == 0);
+  ASSERT(registered_observers_.empty());
 }
 
-void ByteInserter::RegisterObserver(ByteObserver observer) {
+void ByteInserter::RegisterObserver(const ByteObserver& observer) {
   registered_observers_.push_back(observer);
 }
 
@@ -37,10 +37,14 @@
   return observer;
 }
 
-void ByteInserter::insert_byte(uint8_t byte) {
+void ByteInserter::on_byte(uint8_t byte) {
   for (auto& observer : registered_observers_) {
     observer.OnByte(byte);
   }
+}
+
+void ByteInserter::insert_byte(uint8_t byte) {
+  on_byte(byte);
   std::back_insert_iterator<std::vector<uint8_t>>::operator=(byte);
 }
 
diff --git a/gd/packet/byte_inserter.h b/gd/packet/byte_inserter.h
index 2d49b33..6d33aee 100644
--- a/gd/packet/byte_inserter.h
+++ b/gd/packet/byte_inserter.h
@@ -31,12 +31,15 @@
   ByteInserter(std::vector<uint8_t>& vector);
   virtual ~ByteInserter();
 
-  void insert_byte(uint8_t byte);
+  virtual void insert_byte(uint8_t byte);
 
-  void RegisterObserver(ByteObserver observer);
+  void RegisterObserver(const ByteObserver& observer);
 
   ByteObserver UnregisterObserver();
 
+ protected:
+  void on_byte(uint8_t);
+
  private:
   std::vector<ByteObserver> registered_observers_;
 };
diff --git a/gd/packet/fragmenting_inserter.cc b/gd/packet/fragmenting_inserter.cc
new file mode 100644
index 0000000..90f87c6
--- /dev/null
+++ b/gd/packet/fragmenting_inserter.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "packet/fragmenting_inserter.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+FragmentingInserter::FragmentingInserter(size_t mtu,
+                                         std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator)
+    : BitInserter(to_construct_bit_inserter_), mtu_(mtu), curr_packet_(std::make_unique<RawBuilder>(mtu)),
+      iterator_(iterator) {}
+
+void FragmentingInserter::insert_bits(uint8_t byte, size_t num_bits) {
+  ASSERT(curr_packet_ != nullptr);
+  size_t total_bits = num_bits + num_saved_bits_;
+  uint16_t new_value = static_cast<uint8_t>(saved_bits_) | (static_cast<uint16_t>(byte) << num_saved_bits_);
+  if (total_bits >= 8) {
+    uint8_t new_byte = static_cast<uint8_t>(new_value);
+    on_byte(new_byte);
+    curr_packet_->AddOctets1(new_byte);
+    if (curr_packet_->size() >= mtu_) {
+      iterator_ = std::move(curr_packet_);
+      curr_packet_ = std::make_unique<RawBuilder>(mtu_);
+    }
+    total_bits -= 8;
+    new_value = new_value >> 8;
+  }
+  num_saved_bits_ = total_bits;
+  uint8_t mask = static_cast<uint8_t>(0xff) >> (8 - num_saved_bits_);
+  saved_bits_ = static_cast<uint8_t>(new_value) & mask;
+}
+
+void FragmentingInserter::finalize() {
+  if (curr_packet_->size() != 0) {
+    iterator_ = std::move(curr_packet_);
+  }
+  curr_packet_.reset();
+}
+
+}  // namespace packet
+}  // namespace bluetooth
diff --git a/gd/packet/fragmenting_inserter.h b/gd/packet/fragmenting_inserter.h
new file mode 100644
index 0000000..ff23a09
--- /dev/null
+++ b/gd/packet/fragmenting_inserter.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <cstdint>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace packet {
+
+class FragmentingInserter : public BitInserter {
+ public:
+  FragmentingInserter(size_t mtu, std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator);
+
+  void insert_bits(uint8_t byte, size_t num_bits) override;
+
+  void finalize();
+
+ protected:
+  std::vector<uint8_t> to_construct_bit_inserter_;
+  size_t mtu_;
+  std::unique_ptr<RawBuilder> curr_packet_;
+  std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator_;
+};
+
+}  // namespace packet
+}  // namespace bluetooth
diff --git a/gd/packet/fragmenting_inserter_unittest.cc b/gd/packet/fragmenting_inserter_unittest.cc
new file mode 100644
index 0000000..6179959
--- /dev/null
+++ b/gd/packet/fragmenting_inserter_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ * 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 "packet/fragmenting_inserter.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+
+using bluetooth::packet::FragmentingInserter;
+using std::vector;
+
+namespace bluetooth {
+namespace packet {
+
+TEST(FragmentingInserterTest, addMoreBits) {
+  std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+                                 0b10100000 /* filled with 1010 */};
+  std::vector<std::unique_ptr<RawBuilder>> fragments;
+
+  FragmentingInserter it(result.size(), std::back_insert_iterator(fragments));
+
+  for (size_t i = 0; i < 9; i++) {
+    it.insert_bits(static_cast<uint8_t>(i), i);
+  }
+  it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+
+  it.finalize();
+
+  ASSERT_EQ(1, fragments.size());
+
+  std::vector<uint8_t> bytes;
+  BitInserter bit_inserter(bytes);
+  fragments[0]->Serialize(bit_inserter);
+
+  ASSERT_EQ(result.size(), bytes.size());
+  for (size_t i = 0; i < bytes.size(); i++) {
+    ASSERT_EQ(result[i], bytes[i]);
+  }
+}
+
+TEST(FragmentingInserterTest, observerTest) {
+  std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+                                 0b10100000 /* filled with 1010 */};
+  std::vector<std::unique_ptr<RawBuilder>> fragments;
+
+  FragmentingInserter it(result.size() + 1, std::back_insert_iterator(fragments));
+
+  std::vector<uint8_t> copy;
+
+  uint64_t checksum = 0x0123456789abcdef;
+  it.RegisterObserver(ByteObserver([&copy](uint8_t byte) { copy.push_back(byte); }, [checksum]() { return checksum; }));
+
+  for (size_t i = 0; i < 9; i++) {
+    it.insert_bits(static_cast<uint8_t>(i), i);
+  }
+  it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+  it.finalize();
+
+  ASSERT_EQ(1, fragments.size());
+
+  std::vector<uint8_t> bytes;
+  BitInserter bit_inserter(bytes);
+  fragments[0]->Serialize(bit_inserter);
+
+  ASSERT_EQ(result.size(), bytes.size());
+  for (size_t i = 0; i < bytes.size(); i++) {
+    ASSERT_EQ(result[i], bytes[i]);
+  }
+
+  ASSERT_EQ(result.size(), copy.size());
+  for (size_t i = 0; i < copy.size(); i++) {
+    ASSERT_EQ(result[i], copy[i]);
+  }
+
+  ByteObserver observer = it.UnregisterObserver();
+  ASSERT_EQ(checksum, observer.GetValue());
+}
+
+constexpr size_t kPacketSize = 128;
+class FragmentingTest : public ::testing::TestWithParam<size_t> {
+ public:
+  void StartUp() {
+    counts_.reserve(kPacketSize);
+    for (size_t i = 0; i < kPacketSize; i++) {
+      counts_.push_back(static_cast<uint8_t>(i));
+    }
+  }
+  void ShutDown() {
+    counts_.clear();
+  }
+  std::vector<uint8_t> counts_;
+};
+
+TEST_P(FragmentingTest, mtuFragmentTest) {
+  size_t mtu = GetParam();
+  std::vector<std::unique_ptr<RawBuilder>> fragments;
+  FragmentingInserter it(mtu, std::back_insert_iterator(fragments));
+
+  RawBuilder original_packet(counts_);
+  ASSERT_EQ(counts_.size(), original_packet.size());
+
+  original_packet.Serialize(it);
+  it.finalize();
+
+  size_t expected_fragments = counts_.size() / mtu;
+  if (counts_.size() % mtu != 0) {
+    expected_fragments++;
+  }
+  ASSERT_EQ(expected_fragments, fragments.size());
+
+  std::vector<std::vector<uint8_t>> serialized_fragments;
+  for (size_t f = 0; f < fragments.size(); f++) {
+    serialized_fragments.emplace_back(mtu);
+    BitInserter bit_inserter(serialized_fragments[f]);
+    fragments[f]->Serialize(bit_inserter);
+    if (f + 1 == fragments.size() && (counts_.size() % mtu != 0)) {
+      ASSERT_EQ(serialized_fragments[f].size(), counts_.size() % mtu);
+    } else {
+      ASSERT_EQ(serialized_fragments[f].size(), mtu);
+    }
+    for (size_t b = 0; b < serialized_fragments[f].size(); b++) {
+      EXPECT_EQ(counts_[f * mtu + b], serialized_fragments[f][b]);
+    }
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(chopomatic, FragmentingTest, ::testing::Range<size_t>(1, kPacketSize + 1));
+
+}  // namespace packet
+}  // namespace bluetooth
diff --git a/gd/packet/iterator.cc b/gd/packet/iterator.cc
index 5167806..f924b05 100644
--- a/gd/packet/iterator.cc
+++ b/gd/packet/iterator.cc
@@ -25,9 +25,10 @@
 Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
   data_ = data;
   index_ = offset;
-  length_ = 0;
+  begin_ = 0;
+  end_ = 0;
   for (auto& view : data) {
-    length_ += view.size();
+    end_ += view.size();
   }
 }
 
@@ -93,9 +94,10 @@
 
 template <bool little_endian>
 Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
-  data_ = itr.data_;
-  index_ = itr.index_;
-
+  this->data_ = itr.data_;
+  this->begin_ = itr.begin_;
+  this->end_ = itr.end_;
+  this->index_ = itr.index_;
   return *this;
 }
 
@@ -131,7 +133,7 @@
 
 template <bool little_endian>
 uint8_t Iterator<little_endian>::operator*() const {
-  ASSERT_LOG(index_ < length_, "Index %zu out of bounds: %zu", index_, length_);
+  ASSERT_LOG(index_ < end_ && !(begin_ > index_), "Index %zu out of bounds: [%zu,%zu)", index_, begin_, end_);
   size_t index = index_;
 
   for (auto view : data_) {
@@ -146,13 +148,29 @@
 
 template <bool little_endian>
 size_t Iterator<little_endian>::NumBytesRemaining() const {
-  if (length_ > index_) {
-    return length_ - index_;
+  if (end_ > index_ && !(begin_ > index_)) {
+    return end_ - index_;
   } else {
     return 0;
   }
 }
 
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::Subrange(size_t index, size_t length) const {
+  Iterator<little_endian> to_return(*this);
+  if (to_return.NumBytesRemaining() > index) {
+    to_return.index_ = to_return.index_ + index;
+    to_return.begin_ = to_return.index_;
+    if (to_return.NumBytesRemaining() >= length) {
+      to_return.end_ = to_return.index_ + length;
+    }
+  } else {
+    to_return.end_ = 0;
+  }
+
+  return to_return;
+}
+
 // Explicit instantiations for both types of Iterators.
 template class Iterator<true>;
 template class Iterator<false>;
diff --git a/gd/packet/iterator.h b/gd/packet/iterator.h
index 422c025..8d927a0 100644
--- a/gd/packet/iterator.h
+++ b/gd/packet/iterator.h
@@ -18,6 +18,7 @@
 
 #include <cstdint>
 #include <forward_list>
+#include <memory>
 
 #include "packet/view.h"
 
@@ -60,6 +61,8 @@
 
   size_t NumBytesRemaining() const;
 
+  Iterator Subrange(size_t index, size_t length) const;
+
   // Get the next sizeof(FixedWidthPODType) bytes and return the filled type
   template <typename FixedWidthPODType>
   FixedWidthPODType extract() {
@@ -77,7 +80,8 @@
  private:
   std::forward_list<View> data_;
   size_t index_;
-  size_t length_;
+  size_t begin_;
+  size_t end_;
 };
 
 }  // namespace packet
diff --git a/gd/packet/packet_view.cc b/gd/packet/packet_view.cc
index 94522ae..badd641 100644
--- a/gd/packet/packet_view.cc
+++ b/gd/packet/packet_view.cc
@@ -99,6 +99,24 @@
   return PacketView<false>(GetSubviewList(begin, end));
 }
 
+template <bool little_endian>
+void PacketView<little_endian>::Append(PacketView to_add) {
+  auto insertion_point = fragments_.begin();
+  size_t remaining_length = length_;
+  while (remaining_length > 0) {
+    remaining_length -= insertion_point->size();
+    if (remaining_length > 0) {
+      insertion_point++;
+    }
+  }
+  ASSERT(insertion_point != fragments_.end());
+  for (const auto& fragment : to_add.fragments_) {
+    fragments_.insert_after(insertion_point, fragment);
+    insertion_point++;
+  }
+  length_ += to_add.length_;
+}
+
 // Explicit instantiations for both types of PacketViews.
 template class PacketView<true>;
 template class PacketView<false>;
diff --git a/gd/packet/packet_view.h b/gd/packet/packet_view.h
index 4b2f191..304794c 100644
--- a/gd/packet/packet_view.h
+++ b/gd/packet/packet_view.h
@@ -52,6 +52,9 @@
 
   PacketView<false> GetBigEndianSubview(size_t begin, size_t end) const;
 
+ protected:
+  void Append(PacketView to_add);
+
  private:
   std::forward_list<View> fragments_;
   size_t length_;
diff --git a/gd/packet/packet_view_unittest.cc b/gd/packet/packet_view_unittest.cc
index e88c2cf..0ec2ef4 100644
--- a/gd/packet/packet_view_unittest.cc
+++ b/gd/packet/packet_view_unittest.cc
@@ -20,9 +20,9 @@
 #include <forward_list>
 #include <memory>
 
-#include "common/address.h"
+#include "hci/address.h"
 
-using bluetooth::common::Address;
+using bluetooth::hci::Address;
 using bluetooth::packet::PacketView;
 using bluetooth::packet::View;
 using std::vector;
@@ -91,6 +91,36 @@
  public:
   PacketViewMultiViewTest() = default;
   ~PacketViewMultiViewTest() = default;
+
+  const PacketView<true> single_view =
+      PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+  const PacketView<true> multi_view = PacketView<true>({
+      View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+      View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+      View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+  });
+};
+
+class PacketViewMultiViewAppendTest : public ::testing::Test {
+ public:
+  PacketViewMultiViewAppendTest() = default;
+  ~PacketViewMultiViewAppendTest() = default;
+
+  class AppendedPacketView : public PacketView<true> {
+   public:
+    AppendedPacketView(PacketView<true> first, std::forward_list<PacketView<true>> to_append)
+        : PacketView<true>(first) {
+      for (const auto& packet_view : to_append) {
+        Append(packet_view);
+      }
+    }
+  };
+  const PacketView<true> single_view =
+      PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+  const PacketView<true> multi_view = AppendedPacketView(
+      PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size())}),
+      {PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size())}),
+       PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size())})});
 };
 
 class ViewTest : public ::testing::Test {
@@ -273,7 +303,7 @@
   ASSERT_EQ(0x1f, (*(this->packet))[working_index]);
 }
 
-TYPED_TEST(PacketViewTest, numBytesRemainingTest) {
+TYPED_TEST(IteratorTest, numBytesRemainingTest) {
   auto all = this->packet->begin();
   size_t remaining = all.NumBytesRemaining();
   for (size_t n = remaining; n > 0; n--) {
@@ -288,6 +318,81 @@
   ASSERT_DEATH(*(all++), "");
 }
 
+TYPED_TEST(IteratorTest, subrangeTest) {
+  auto empty = this->packet->begin().Subrange(0, 0);
+  ASSERT_EQ(static_cast<size_t>(0), empty.NumBytesRemaining());
+  ASSERT_DEATH(*empty, "");
+
+  empty = this->packet->begin().Subrange(this->packet->size(), 1);
+  ASSERT_EQ(static_cast<size_t>(0), empty.NumBytesRemaining());
+  ASSERT_DEATH(*empty, "");
+
+  auto all = this->packet->begin();
+  auto fullrange = all.Subrange(0, all.NumBytesRemaining());
+  ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+  ASSERT_EQ(*(all + 1), 1);
+
+  fullrange = all.Subrange(0, all.NumBytesRemaining() + 1);
+  ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+  ASSERT_EQ(*(all + 1), 1);
+
+  fullrange = all.Subrange(0, all.NumBytesRemaining() + 10);
+  ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+  ASSERT_EQ(*(all + 1), 1);
+
+  auto subrange = all.Subrange(0, 1);
+  ASSERT_EQ(1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange), 0);
+
+  subrange = this->packet->begin().Subrange(0, 4);
+  ASSERT_EQ(4, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange + 1), 1);
+
+  subrange = all.Subrange(0, 3);
+  ASSERT_EQ(3, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange + 1), 1);
+
+  subrange = all.Subrange(0, all.NumBytesRemaining() - 1);
+  ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange + 1), 1);
+
+  subrange = all.Subrange(0, all.NumBytesRemaining() - 2);
+  ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange + 1), 1);
+
+  subrange = all.Subrange(1, all.NumBytesRemaining());
+  ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*subrange, 1);
+
+  subrange = all.Subrange(2, all.NumBytesRemaining());
+  ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+  ASSERT_EQ(*subrange, 2);
+
+  subrange = all.Subrange(1, all.NumBytesRemaining() - 1);
+  ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*subrange, 1);
+
+  subrange = all.Subrange(2, all.NumBytesRemaining() - 2);
+  ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+  ASSERT_EQ(*subrange, 2);
+
+  subrange = all.Subrange(1, 1);
+  ASSERT_EQ(1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange), 1);
+
+  subrange = all.Subrange(1, 2);
+  ASSERT_EQ(2, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange), 1);
+
+  subrange = all.Subrange(2, 1);
+  ASSERT_EQ(1, subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange), 2);
+
+  subrange = this->packet->begin().Subrange(this->packet->size() - 1, 2);
+  ASSERT_EQ(static_cast<size_t>(1), subrange.NumBytesRemaining());
+  ASSERT_EQ(*(subrange), this->packet->size() - 1);
+}
+
 using SubviewTestParam = std::pair<size_t, size_t>;
 class SubviewBaseTest : public ::testing::TestWithParam<SubviewTestParam> {
  public:
@@ -408,23 +513,11 @@
   }
 }
 
-TEST(PacketViewMultiViewTest, sizeTest) {
-  PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
-  PacketView<true> multi_view({
-      View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
-  });
+TEST_F(PacketViewMultiViewTest, sizeTest) {
   ASSERT_EQ(single_view.size(), multi_view.size());
 }
 
-TEST(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
-  PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
-  PacketView<true> multi_view({
-      View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
-  });
+TEST_F(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
   auto single_itr = single_view.begin();
   auto multi_itr = multi_view.begin();
   for (size_t i = 0; i < single_view.size(); i++) {
@@ -433,13 +526,7 @@
   ASSERT_DEATH(*multi_itr, "");
 }
 
-TEST(PacketViewMultiViewTest, dereferenceTestBigEndian) {
-  PacketView<false> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
-  PacketView<false> multi_view({
-      View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
-  });
+TEST_F(PacketViewMultiViewTest, dereferenceTestBigEndian) {
   auto single_itr = single_view.begin();
   auto multi_itr = multi_view.begin();
   for (size_t i = 0; i < single_view.size(); i++) {
@@ -448,13 +535,36 @@
   ASSERT_DEATH(*multi_itr, "");
 }
 
-TEST(PacketViewMultiViewTest, arrayOperatorTest) {
-  PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
-  PacketView<true> multi_view({
-      View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
-      View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
-  });
+TEST_F(PacketViewMultiViewTest, arrayOperatorTest) {
+  for (size_t i = 0; i < single_view.size(); i++) {
+    ASSERT_EQ(single_view[i], multi_view[i]);
+  }
+  ASSERT_DEATH(multi_view[single_view.size()], "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, sizeTestAppend) {
+  ASSERT_EQ(single_view.size(), multi_view.size());
+}
+
+TEST_F(PacketViewMultiViewAppendTest, dereferenceTestLittleEndianAppend) {
+  auto single_itr = single_view.begin();
+  auto multi_itr = multi_view.begin();
+  for (size_t i = 0; i < single_view.size(); i++) {
+    ASSERT_EQ(*(single_itr++), *(multi_itr++));
+  }
+  ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, dereferenceTestBigEndianAppend) {
+  auto single_itr = single_view.begin();
+  auto multi_itr = multi_view.begin();
+  for (size_t i = 0; i < single_view.size(); i++) {
+    ASSERT_EQ(*(single_itr++), *(multi_itr++));
+  }
+  ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, arrayOperatorTestAppend) {
   for (size_t i = 0; i < single_view.size(); i++) {
     ASSERT_EQ(single_view[i], multi_view[i]);
   }
diff --git a/gd/packet/parser/Android.bp b/gd/packet/parser/Android.bp
index 0711ade..97f323a 100644
--- a/gd/packet/parser/Android.bp
+++ b/gd/packet/parser/Android.bp
@@ -15,11 +15,13 @@
         "fields/fixed_scalar_field.cc",
         "fields/group_field.cc",
         "fields/packet_field.cc",
+        "fields/padding_field.cc",
         "fields/payload_field.cc",
         "fields/reserved_field.cc",
         "fields/scalar_field.cc",
         "fields/size_field.cc",
         "fields/struct_field.cc",
+        "fields/variable_length_struct_field.cc",
         "checksum_def.cc",
         "custom_field_def.cc",
         "enum_def.cc",
@@ -27,6 +29,7 @@
         "packet_def.cc",
         "parent_def.cc",
         "struct_def.cc",
+        "struct_parser_generator.cc",
         "main.cc",
         "language_y.yy",
         "language_l.ll",
@@ -35,7 +38,6 @@
         "libc++fs",
     ],
     cppflags: [
-        "-Wno-implicit-fallthrough",
         "-fno-exceptions",
         "-O0",
     ],
diff --git a/gd/packet/parser/checksum_def.cc b/gd/packet/parser/checksum_def.cc
index b41770e..8cb1803 100644
--- a/gd/packet/parser/checksum_def.cc
+++ b/gd/packet/parser/checksum_def.cc
@@ -15,7 +15,8 @@
  */
 
 #include "checksum_def.h"
-
+#include "checksum_type_checker.h"
+#include "fields/checksum_field.h"
 #include "util.h"
 
 ChecksumDef::ChecksumDef(std::string name, std::string include, int size) : CustomFieldDef(name, include, size) {}
diff --git a/gd/packet/parser/checksum_def.h b/gd/packet/parser/checksum_def.h
index 1aee9bd..f82b8c3 100644
--- a/gd/packet/parser/checksum_def.h
+++ b/gd/packet/parser/checksum_def.h
@@ -18,9 +18,8 @@
 
 #include <iostream>
 
-#include "checksum_type_checker.h"
 #include "custom_field_def.h"
-#include "fields/checksum_field.h"
+#include "fields/packet_field.h"
 #include "parse_location.h"
 #include "type_def.h"
 
diff --git a/gd/packet/parser/custom_field_def.cc b/gd/packet/parser/custom_field_def.cc
index 5dc9316..3f2076d 100644
--- a/gd/packet/parser/custom_field_def.cc
+++ b/gd/packet/parser/custom_field_def.cc
@@ -57,7 +57,8 @@
   s << GetTypeName() << ";";
 }
 
-void CustomFieldDef::GenCustomFieldCheck(std::ostream& s) const {
-  s << "static_assert(CustomTypeChecker<" << name_ << ">::value, \"";
+void CustomFieldDef::GenCustomFieldCheck(std::ostream& s, bool little_endian) const {
+  s << "static_assert(CustomTypeChecker<" << name_ << ", ";
+  s << (little_endian ? "" : "!") << "kLittleEndian>::value, \"";
   s << name_ << " is not a valid custom field type. Please see README for more details.\");";
 }
diff --git a/gd/packet/parser/custom_field_def.h b/gd/packet/parser/custom_field_def.h
index 62cf363..26b954f 100644
--- a/gd/packet/parser/custom_field_def.h
+++ b/gd/packet/parser/custom_field_def.h
@@ -37,7 +37,7 @@
 
   void GenUsing(std::ostream& s) const;
 
-  void GenCustomFieldCheck(std::ostream& s) const;
+  void GenCustomFieldCheck(std::ostream& s, bool little_endian) const;
 
   const std::string include_;
 };
diff --git a/gd/packet/parser/custom_type_checker.h b/gd/packet/parser/custom_type_checker.h
index 33dc340..5d99622 100644
--- a/gd/packet/parser/custom_type_checker.h
+++ b/gd/packet/parser/custom_type_checker.h
@@ -24,7 +24,7 @@
 namespace bluetooth {
 namespace packet {
 // Checks a custom type has all the necessary functions with the correct signatures.
-template <typename T>
+template <typename T, bool packet_little_endian>
 class CustomTypeChecker {
  public:
   template <class C, void (C::*)(BitInserter&) const>
@@ -33,22 +33,17 @@
   template <class C, size_t (C::*)() const>
   struct SizeChecker {};
 
-  template <class C, Iterator<true> (*)(std::vector<C>& vec, Iterator<true> it)>
+  template <class C, bool little_endian, std::optional<Iterator<little_endian>> (*)(C* vec, Iterator<little_endian> it)>
   struct ParseChecker {};
 
-  template <class C, Iterator<false> (*)(std::vector<C>& vec, Iterator<false> it)>
-  struct ParseCheckerBigEndian {};
+  template <class C, bool little_endian>
+  static int Test(SerializeChecker<C, &C::Serialize>*, SizeChecker<C, &C::size>*,
+                  ParseChecker<C, little_endian, &C::Parse>*);
 
-  template <class C>
-  static int Test(SerializeChecker<C, &C::Serialize>*, SizeChecker<C, &C::size>*, ParseChecker<C, &C::Parse>*);
-
-  template <class C>
-  static int Test(SerializeChecker<C, &C::Serialize>*, SizeChecker<C, &C::size>*, ParseCheckerBigEndian<C, &C::Parse>*);
-
-  template <class C>
+  template <class C, bool little_endian>
   static char Test(...);
 
-  static constexpr bool value = (sizeof(Test<T>(0, 0, 0)) == sizeof(int));
+  static constexpr bool value = (sizeof(Test<T, packet_little_endian>(0, 0, 0)) == sizeof(int));
 };
 }  // namespace packet
 }  // namespace bluetooth
diff --git a/gd/packet/parser/declarations.h b/gd/packet/parser/declarations.h
index 21470e7..549ddc4 100644
--- a/gd/packet/parser/declarations.h
+++ b/gd/packet/parser/declarations.h
@@ -30,6 +30,10 @@
 class Declarations {
  public:
   void AddTypeDef(std::string name, TypeDef* def) {
+    auto it = type_defs_.find(name);
+    if (it != type_defs_.end()) {
+      ERROR() << "Redefinition of Type " << name;
+    }
     type_defs_.insert(std::pair(name, def));
     type_defs_queue_.push_back(std::pair(name, def));
   }
@@ -44,6 +48,10 @@
   }
 
   void AddPacketDef(std::string name, PacketDef def) {
+    auto it = packet_defs_.find(name);
+    if (it != packet_defs_.end()) {
+      ERROR() << "Redefinition of Packet " << name;
+    }
     packet_defs_.insert(std::pair(name, def));
     packet_defs_queue_.push_back(std::pair(name, def));
   }
@@ -58,6 +66,10 @@
   }
 
   void AddGroupDef(std::string name, FieldList* group_def) {
+    auto it = group_defs_.find(name);
+    if (it != group_defs_.end()) {
+      ERROR() << "Redefinition of group " << name;
+    }
     group_defs_.insert(std::pair(name, group_def));
   }
 
diff --git a/gd/packet/parser/enum_def.cc b/gd/packet/parser/enum_def.cc
index 96c49ad..8b90426 100644
--- a/gd/packet/parser/enum_def.cc
+++ b/gd/packet/parser/enum_def.cc
@@ -22,9 +22,12 @@
 #include "fields/enum_field.h"
 #include "util.h"
 
-EnumDef::EnumDef(std::string name, int size) : TypeDef(name, size){};
+EnumDef::EnumDef(std::string name, int size) : TypeDef(name, size) {}
 
 void EnumDef::AddEntry(std::string name, uint32_t value) {
+  if (!util::IsEnumCase(name)) {
+    ERROR() << __func__ << ": Enum " << name << "(" << value << ") should be all uppercase with underscores";
+  }
   if (value > util::GetMaxValueForBits(size_)) {
     ERROR() << __func__ << ": Value of " << name << "(" << value << ") is greater than the max possible value for enum "
             << name_ << "(" << util::GetMaxValueForBits(size_) << ")\n";
diff --git a/gd/packet/parser/enum_gen.cc b/gd/packet/parser/enum_gen.cc
index 769a43a..4bd5a26 100644
--- a/gd/packet/parser/enum_gen.cc
+++ b/gd/packet/parser/enum_gen.cc
@@ -20,7 +20,7 @@
 
 #include "util.h"
 
-EnumGen::EnumGen(EnumDef e) : e_(e){};
+EnumGen::EnumGen(EnumDef e) : e_(std::move(e)) {}
 
 void EnumGen::GenDefinition(std::ostream& stream) {
   stream << "enum class ";
@@ -33,6 +33,14 @@
   stream << "};\n";
 }
 
+void EnumGen::GenDefinitionPybind11(std::ostream& stream) {
+  stream << "py::enum_<" << e_.name_ << ">(m, \"" << e_.name_ << "\")";
+  for (const auto& pair : e_.constants_) {
+    stream << ".value(\"" << pair.second << "\", " << e_.name_ << "::" << pair.second << ")";
+  }
+  stream << ";\n";
+}
+
 void EnumGen::GenLogging(std::ostream& stream) {
   // Print out the switch statement that converts all the constants to strings.
   stream << "inline std::string " << e_.name_ << "Text(const " << e_.name_ << "& param) {";
diff --git a/gd/packet/parser/enum_gen.h b/gd/packet/parser/enum_gen.h
index f3483dd..be16559 100644
--- a/gd/packet/parser/enum_gen.h
+++ b/gd/packet/parser/enum_gen.h
@@ -27,6 +27,8 @@
 
   void GenDefinition(std::ostream& stream);
 
+  void GenDefinitionPybind11(std::ostream& stream);
+
   void GenLogging(std::ostream& stream);
 
   EnumDef e_;
diff --git a/gd/packet/parser/fields/all_fields.h b/gd/packet/parser/fields/all_fields.h
index cf51a3f..8c0aeee 100644
--- a/gd/packet/parser/fields/all_fields.h
+++ b/gd/packet/parser/fields/all_fields.h
@@ -27,9 +27,11 @@
 #include "fields/fixed_enum_field.h"
 #include "fields/fixed_scalar_field.h"
 #include "fields/group_field.h"
+#include "fields/padding_field.h"
 #include "fields/payload_field.h"
 #include "fields/reserved_field.h"
 #include "fields/scalar_field.h"
 #include "fields/size_field.h"
 #include "fields/struct_field.h"
+#include "fields/variable_length_struct_field.h"
 #include "fields/vector_field.h"
diff --git a/gd/packet/parser/fields/array_field.cc b/gd/packet/parser/fields/array_field.cc
index 2dca9c1..37dea16 100644
--- a/gd/packet/parser/fields/array_field.cc
+++ b/gd/packet/parser/fields/array_field.cc
@@ -15,25 +15,28 @@
  */
 
 #include "fields/array_field.h"
+
+#include "fields/custom_field.h"
+#include "fields/scalar_field.h"
 #include "util.h"
 
 const std::string ArrayField::kFieldType = "ArrayField";
 
-ArrayField::ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc)
-    : PacketField(name, loc), element_size_(element_size), fixed_size_(fixed_size) {
-  if (element_size_ > 64 || element_size_ < 0)
-    ERROR(this) << __func__ << ": Not implemented for element size = " << element_size_;
-  // Make sure the element_size is a multiple of 8.
+ArrayField::ArrayField(std::string name, int element_size, int array_size, ParseLocation loc)
+    : PacketField(name, loc), element_field_(new ScalarField("val", element_size, loc)), element_size_(element_size),
+      array_size_(array_size) {
+  if (element_size > 64 || element_size < 0)
+    ERROR(this) << __func__ << ": Not implemented for element size = " << element_size;
   if (element_size % 8 != 0) {
     ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size << ")";
   }
 }
 
-ArrayField::ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc)
-    : PacketField(name, loc), element_size_(type_def->size_), type_def_(type_def), fixed_size_(fixed_size) {
-  // If the element type is not variable sized, make sure that it is byte aligned.
-  if (type_def_->size_ != -1 && type_def_->size_ % 8 != 0) {
-    ERROR(this) << "Can only have arrays with elements that are byte aligned (" << type_def_->size_ << ")";
+ArrayField::ArrayField(std::string name, TypeDef* type_def, int array_size, ParseLocation loc)
+    : PacketField(name, loc), element_field_(type_def->GetNewField("val", loc)),
+      element_size_(element_field_->GetSize()), array_size_(array_size) {
+  if (!element_size_.empty() && element_size_.bits() % 8 != 0) {
+    ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_ << ")";
   }
 }
 
@@ -42,15 +45,18 @@
 }
 
 Size ArrayField::GetSize() const {
-  if (element_size_ != -1) {
-    return Size(fixed_size_ * element_size_);
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    return Size(array_size_ * element_size_.bits());
   }
   return Size();
 }
 
 Size ArrayField::GetBuilderSize() const {
-  if (element_size_ != -1) {
-    std::string ret = "(" + std::to_string(fixed_size_) + " * " + std::to_string(element_size_) + ")";
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    return GetSize();
+  } else if (element_field_->BuilderParameterMustBeMoved()) {
+    std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+                      "_) { length += elem->size() * 8; } return length; }()";
     return ret;
   } else {
     std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
@@ -59,64 +65,84 @@
   }
 }
 
-std::string ArrayField::GetDataType() const {
-  if (type_def_ != nullptr) {
-    return "std::array<" + type_def_->name_ + "," + std::to_string(fixed_size_) + ">";
+Size ArrayField::GetStructSize() const {
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    return GetSize();
+  } else if (element_field_->BuilderParameterMustBeMoved()) {
+    std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
+                      "_) { length += elem->size() * 8; } return length; }()";
+    return ret;
+  } else {
+    std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
+                      "_) { length += elem.size() * 8; } return length; }()";
+    return ret;
   }
-  return "std::array<" + util::GetTypeForSize(element_size_) + "," + std::to_string(fixed_size_) + ">";
 }
 
-void ArrayField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
-  GenBounds(s, start_offset, end_offset, GetSize());
+std::string ArrayField::GetDataType() const {
+  return "std::array<" + element_field_->GetDataType() + "," + std::to_string(array_size_) + ">";
+}
 
-  s << "auto it = begin_it + field_begin;";
-
-  // Add the element size so that we will extract as many elements as we can.
-  s << GetDataType() << " value;";
-  if (element_size_ != -1) {
-    std::string type = (type_def_ != nullptr) ? type_def_->name_ : util::GetTypeForSize(element_size_);
-    s << GetDataType() << "::iterator ret_it = value.begin();";
-    s << "while (it + sizeof(" << type << ") <= begin_it + field_end) {";
-    s << "*ret_it = it.extract<" << type << ">();";
-    s << "ret_it++;";
-    s << "}";
+void ArrayField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const {
+  s << GetDataType() << "::iterator ret_it = " << GetName() << "_ptr->begin();";
+  s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;";
+  if (!element_size_.empty()) {
+    s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() >= " << element_size_.bytes();
+    s << " && ret_it < " << GetName() << "_ptr->end()) {";
   } else {
-    s << "std::size_t ret_idx = 0;";
-    s << "while (it < begin_it + field_end) {";
-    s << "it = " << type_def_->name_ << "::ParseArray(value, &ret_idx, it);";
-    s << "ret_idx++;";
-    s << "}";
+    s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() > 0 ";
+    s << " && ret_it < " << GetName() << "_ptr->end()) {";
   }
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;";
+  } else {
+    s << element_field_->GetDataType() << "* " << element_field_->GetName() << "_ptr = ret_it;";
+  }
+  element_field_->GenExtractor(s, num_leading_bits, for_struct);
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    s << "*ret_it = std::move(" << element_field_->GetName() << "_ptr);";
+  }
+  s << "ret_it++;";
+  s << "}";
+}
+
+std::string ArrayField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
 }
 
 void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  s << GetDataType();
-  s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() {";
+  s << GetDataType() << " " << GetGetterFunctionName() << "() {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
-  s << "auto begin_it = begin();";
+  s << "auto to_bound = begin();";
 
-  GenExtractor(s, start_offset, end_offset);
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << GetDataType() << " " << GetName() << "_value;";
+  s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+  GenExtractor(s, num_leading_bits, false);
 
-  s << "return value;";
+  s << "return " << GetName() << "_value;";
   s << "}\n";
 }
 
-bool ArrayField::GenBuilderParameter(std::ostream& s) const {
-  if (type_def_ != nullptr) {
-    s << "const std::array<" << type_def_->GetTypeName() << "," << fixed_size_ << ">& " << GetName();
+std::string ArrayField::GetBuilderParameterType() const {
+  std::stringstream ss;
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    ss << "std::array<" << element_field_->GetDataType() << "," << array_size_ << ">";
   } else {
-    s << "const std::array<" << util::GetTypeForSize(element_size_) << "," << fixed_size_ << ">& " << GetName();
+    ss << "const std::array<" << element_field_->GetDataType() << "," << array_size_ << ">&";
   }
-  return true;
+  return ss.str();
+}
+
+bool ArrayField::BuilderParameterMustBeMoved() const {
+  return element_field_->BuilderParameterMustBeMoved();
 }
 
 bool ArrayField::GenBuilderMember(std::ostream& s) const {
-  if (type_def_ != nullptr) {
-    s << "std::array<" << type_def_->GetTypeName() << "," << fixed_size_ << "> " << GetName();
-  } else {
-    s << "std::array<" << util::GetTypeForSize(element_size_) << "," << fixed_size_ << "> " << GetName();
-  }
+  s << "std::array<" << element_field_->GetDataType() << "," << array_size_ << "> " << GetName();
   return true;
 }
 
@@ -129,20 +155,8 @@
 }
 
 void ArrayField::GenInserter(std::ostream& s) const {
-  s << "for (const auto& val : " << GetName() << "_) {";
-  if (IsEnumArray()) {
-    s << "insert(static_cast<" << util::GetTypeForSize(type_def_->size_) << ">(val), i, " << type_def_->size_ << ");";
-  } else if (IsCustomFieldArray()) {
-    if (type_def_->size_ == -1) {
-      s << "val.Serialize(i);";
-    } else {
-      s << "insert(val, i);";
-    }
-  } else if (IsStructArray()) {
-    s << "val.Serialize(i);";
-  } else {
-    s << "insert(val, i, " << element_size_ << ");";
-  }
+  s << "for (const auto& val_ : " << GetName() << "_) {";
+  element_field_->GenInserter(s);
   s << "}\n";
 }
 
@@ -154,14 +168,10 @@
   // be done here.
 }
 
-bool ArrayField::IsEnumArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::ENUM;
+bool ArrayField::IsContainerField() const {
+  return true;
 }
 
-bool ArrayField::IsCustomFieldArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
-}
-
-bool ArrayField::IsStructArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
+const PacketField* ArrayField::GetElementField() const {
+  return element_field_;
 }
diff --git a/gd/packet/parser/fields/array_field.h b/gd/packet/parser/fields/array_field.h
index 1892f57..dd49f26 100644
--- a/gd/packet/parser/fields/array_field.h
+++ b/gd/packet/parser/fields/array_field.h
@@ -16,12 +16,9 @@
 
 #pragma once
 
-#include "custom_field_def.h"
-#include "enum_def.h"
-#include "fields/count_field.h"
 #include "fields/packet_field.h"
-#include "fields/size_field.h"
 #include "parse_location.h"
+#include "type_def.h"
 
 class ArrayField : public PacketField {
  public:
@@ -37,13 +34,19 @@
 
   virtual Size GetBuilderSize() const override;
 
+  virtual Size GetStructSize() const override;
+
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
+
+  virtual bool BuilderParameterMustBeMoved() const override;
 
   virtual bool GenBuilderMember(std::ostream& s) const override;
 
@@ -55,17 +58,15 @@
 
   virtual void GenValidator(std::ostream&) const override;
 
-  bool IsEnumArray() const;
+  virtual bool IsContainerField() const override;
 
-  bool IsCustomFieldArray() const;
-
-  bool IsStructArray() const;
+  virtual const PacketField* GetElementField() const override;
 
   const std::string name_;
 
-  const int element_size_{-1};  // in bits
-  const TypeDef* type_def_{nullptr};
+  const PacketField* element_field_{nullptr};
 
-  // Fixed size array or dynamic size, size is always in bytes, unless it is count.
-  const int fixed_size_{-1};
+  const Size element_size_{};
+
+  const int array_size_{-1};
 };
diff --git a/gd/packet/parser/fields/body_field.cc b/gd/packet/parser/fields/body_field.cc
index 564831b..5e00b68 100644
--- a/gd/packet/parser/fields/body_field.cc
+++ b/gd/packet/parser/fields/body_field.cc
@@ -33,12 +33,16 @@
   return "BodyType";
 }
 
-void BodyField::GenExtractor(std::ostream&, Size, Size) const {}
+void BodyField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string BodyField::GetGetterFunctionName() const {
+  return "";
+}
 
 void BodyField::GenGetter(std::ostream&, Size, Size) const {}
 
-bool BodyField::GenBuilderParameter(std::ostream&) const {
-  return false;
+std::string BodyField::GetBuilderParameterType() const {
+  return "";
 }
 
 bool BodyField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/body_field.h b/gd/packet/parser/fields/body_field.h
index 3881f99..ce4ede7 100644
--- a/gd/packet/parser/fields/body_field.h
+++ b/gd/packet/parser/fields/body_field.h
@@ -32,11 +32,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream&, Size, Size) const override;
 
-  virtual bool GenBuilderParameter(std::ostream&) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/checksum_field.cc b/gd/packet/parser/fields/checksum_field.cc
index a5cea67..4647992 100644
--- a/gd/packet/parser/fields/checksum_field.cc
+++ b/gd/packet/parser/fields/checksum_field.cc
@@ -30,7 +30,11 @@
   return type_name_;
 }
 
-void ChecksumField::GenExtractor(std::ostream&, Size, Size) const {}
+void ChecksumField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ChecksumField::GetGetterFunctionName() const {
+  return "";
+}
 
 void ChecksumField::GenGetter(std::ostream&, Size, Size) const {}
 
diff --git a/gd/packet/parser/fields/checksum_field.h b/gd/packet/parser/fields/checksum_field.h
index d4c0ad0..c15f023 100644
--- a/gd/packet/parser/fields/checksum_field.h
+++ b/gd/packet/parser/fields/checksum_field.h
@@ -30,7 +30,9 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
diff --git a/gd/packet/parser/fields/checksum_start_field.cc b/gd/packet/parser/fields/checksum_start_field.cc
index b90f073..5531c5a 100644
--- a/gd/packet/parser/fields/checksum_start_field.cc
+++ b/gd/packet/parser/fields/checksum_start_field.cc
@@ -34,13 +34,16 @@
   return "There's no type for Checksum Start fields";
 }
 
-void ChecksumStartField::GenExtractor(std::ostream&, Size, Size) const {}
+void ChecksumStartField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ChecksumStartField::GetGetterFunctionName() const {
+  return "";
+}
 
 void ChecksumStartField::GenGetter(std::ostream&, Size, Size) const {}
 
-bool ChecksumStartField::GenBuilderParameter(std::ostream&) const {
-  // There is no builder parameter for a size field
-  return false;
+std::string ChecksumStartField::GetBuilderParameterType() const {
+  return "";
 }
 
 bool ChecksumStartField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/checksum_start_field.h b/gd/packet/parser/fields/checksum_start_field.h
index ef58356..c63806b 100644
--- a/gd/packet/parser/fields/checksum_start_field.h
+++ b/gd/packet/parser/fields/checksum_start_field.h
@@ -33,11 +33,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream&) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/custom_field.cc b/gd/packet/parser/fields/custom_field.cc
index 55ab97d..4e387f8 100644
--- a/gd/packet/parser/fields/custom_field.cc
+++ b/gd/packet/parser/fields/custom_field.cc
@@ -39,27 +39,41 @@
   return type_name_;
 }
 
-void CustomField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
-  GenBounds(s, start_offset, end_offset, Size());
-  s << " auto subview = GetLittleEndianSubview(field_begin, field_end); ";
-  s << "auto it = subview.begin();";
-  s << "std::vector<" << GetDataType() << "> vec;";
-  s << GetDataType() << "::Parse(vec, it);";
+void CustomField::GenExtractor(std::ostream& s, int, bool) const {
+  s << "auto optional_it = ";
+  s << GetDataType() << "::Parse( " << GetName() << "_ptr, " << GetName() << "_it);";
+  s << "if (optional_it) {";
+  s << GetName() << "_it = *optional_it;";
+  s << "} else {";
+  s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_it.NumBytesRemaining();";
+  s << GetName() << "_ptr = nullptr;";
+  s << "}";
+}
+
+std::string CustomField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
 }
 
 void CustomField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  s << "std::vector<" << GetDataType() << "> Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+  s << "std::unique_ptr<" << GetDataType() << "> " << GetGetterFunctionName() << "() const {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
+  s << "auto to_bound = begin();";
 
-  GenExtractor(s, start_offset, end_offset);
-  s << "return vec;";
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << "std::unique_ptr<" << GetDataType() << "> " << GetName() << "_value";
+  s << " = std::make_unique<" << GetDataType() << ">();";
+  s << GetDataType() << "* " << GetName() << "_ptr = " << GetName() << "_value.get();";
+  GenExtractor(s, num_leading_bits, false);
+  s << "if (" << GetName() << "_ptr == nullptr) {" << GetName() << "_value.reset(); }";
+  s << "return " << GetName() << "_value;";
   s << "}\n";
 }
 
-bool CustomField::GenBuilderParameter(std::ostream& s) const {
-  s << GetDataType() << " " << GetName();
-  return true;
+std::string CustomField::GetBuilderParameterType() const {
+  return GetDataType();
 }
 
 bool CustomField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/custom_field.h b/gd/packet/parser/fields/custom_field.h
index 86fefd2..621a3c8 100644
--- a/gd/packet/parser/fields/custom_field.h
+++ b/gd/packet/parser/fields/custom_field.h
@@ -33,11 +33,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/custom_field_fixed_size.cc b/gd/packet/parser/fields/custom_field_fixed_size.cc
index 08d3a0e..029f0aa 100644
--- a/gd/packet/parser/fields/custom_field_fixed_size.cc
+++ b/gd/packet/parser/fields/custom_field_fixed_size.cc
@@ -30,20 +30,21 @@
   return type_name_;
 }
 
-void CustomFieldFixedSize::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
-  int field_size = GetSize().bits();
-
+int CustomFieldFixedSize::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
   if (!start_offset.empty()) {
     // Default to start if available.
-    s << "auto it = begin_it + (" << start_offset << ") / 8;";
+    s << "auto " << GetName() << "_it = to_bound + (" << start_offset << ") / 8;";
   } else if (!end_offset.empty()) {
-    Size byte_offset = Size(field_size) + end_offset;
-    s << "auto it = end_it - (" << byte_offset << ") / 8;";
+    Size byte_offset = size + end_offset;
+    s << "auto " << GetName() << "_it = to_bound (+ to_bound.NumBytesRemaining() - (" << byte_offset << ") / 8);";
   } else {
     ERROR(this) << "Ambiguous offset for field.";
   }
+  return 0;  // num_leading_bits
+}
 
-  s << GetDataType() << " value = it.extract<" << GetDataType() << ">();";
+void CustomFieldFixedSize::GenExtractor(std::ostream& s, int, bool) const {
+  s << "*" << GetName() << "_ptr = " << GetName() << "_it.extract<" << GetDataType() << ">();";
 }
 
 bool CustomFieldFixedSize::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/custom_field_fixed_size.h b/gd/packet/parser/fields/custom_field_fixed_size.h
index 5a11c0d..bd19eb0 100644
--- a/gd/packet/parser/fields/custom_field_fixed_size.h
+++ b/gd/packet/parser/fields/custom_field_fixed_size.h
@@ -29,7 +29,9 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const override;
+
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/group_field.cc b/gd/packet/parser/fields/group_field.cc
index 7b0dfa6..6c9ade9 100644
--- a/gd/packet/parser/fields/group_field.cc
+++ b/gd/packet/parser/fields/group_field.cc
@@ -44,17 +44,22 @@
   return "";
 }
 
-void GroupField::GenExtractor(std::ostream&, Size, Size) const {
+void GroupField::GenExtractor(std::ostream&, int, bool) const {
   ERROR(this) << "GenExtractor should never be called.";
 }
 
+std::string GroupField::GetGetterFunctionName() const {
+  ERROR(this) << "GetGetterFunctionName should never be called.";
+  return "";
+}
+
 void GroupField::GenGetter(std::ostream&, Size, Size) const {
   ERROR(this) << "GenGetter should never be called.";
 }
 
-bool GroupField::GenBuilderParameter(std::ostream&) const {
-  ERROR(this) << "GenBuilderParameter should never be called";
-  return false;
+std::string GroupField::GetBuilderParameterType() const {
+  ERROR(this) << "GetBuilderParameterType should never be called";
+  return "";
 }
 
 bool GroupField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/group_field.h b/gd/packet/parser/fields/group_field.h
index 407a37b..57e0165 100644
--- a/gd/packet/parser/fields/group_field.h
+++ b/gd/packet/parser/fields/group_field.h
@@ -37,11 +37,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream&, Size, Size) const override;
 
-  virtual bool GenBuilderParameter(std::ostream&) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/packet_field.cc b/gd/packet/parser/fields/packet_field.cc
index 6b2b2de..7b0bdb7 100644
--- a/gd/packet/parser/fields/packet_field.cc
+++ b/gd/packet/parser/fields/packet_field.cc
@@ -16,6 +16,8 @@
 
 #include "fields/packet_field.h"
 
+#include "util.h"
+
 PacketField::PacketField(std::string name, ParseLocation loc) : loc_(loc), name_(name) {}
 
 std::string PacketField::GetDebugName() const {
@@ -34,11 +36,15 @@
   return GetSize();
 }
 
-void PacketField::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size field_size) const {
+Size PacketField::GetStructSize() const {
+  return GetSize();
+}
+
+int PacketField::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
   // In order to find field_begin and field_end, we must have two of the three Sizes.
-  if ((start_offset.empty() && field_size.empty()) || (start_offset.empty() && end_offset.empty()) ||
-      (end_offset.empty() && field_size.empty())) {
-    ERROR(this) << "GenBounds called without enough information. " << start_offset << end_offset << field_size;
+  if ((start_offset.empty() && size.empty()) || (start_offset.empty() && end_offset.empty()) ||
+      (end_offset.empty() && size.empty())) {
+    ERROR(this) << "GenBounds called without enough information. " << start_offset << end_offset << size;
   }
 
   if (start_offset.bits() % 8 != 0 || end_offset.bits() % 8 != 0) {
@@ -48,21 +54,49 @@
   if (!start_offset.empty()) {
     s << "size_t field_begin = (" << start_offset << ") / 8;";
   } else {
-    s << "size_t field_begin = end_index - (" << end_offset << " + " << field_size << ") / 8;";
+    s << "size_t field_begin = end_index - (" << end_offset << " + " << size << ") / 8;";
   }
 
   if (!end_offset.empty()) {
     s << "size_t field_end = end_index - (" << end_offset << ") / 8;";
     // If the field has a known size, use the minimum for the end
-    if (!field_size.empty()) {
-      s << "size_t field_sized_end = field_begin + (" << field_size << ") / 8;";
+    if (!size.empty()) {
+      s << "size_t field_sized_end = field_begin + (" << size << ") / 8;";
       s << "if (field_sized_end < field_end) { field_end = field_sized_end; }";
     }
   } else {
-    s << "size_t field_end = field_begin + (" << field_size << ") / 8;";
+    s << "size_t field_end = field_begin + (" << size << ") / 8;";
+    s << "if (field_end > end_index) { field_end = end_index; }";
   }
+  s << "auto " << name_ << "_it = to_bound.Subrange(field_begin, field_end - field_begin); ";
+  return 0;  // num_leading_bits
+}
+
+bool PacketField::GenBuilderParameter(std::ostream& s) const {
+  auto param_type = GetBuilderParameterType();
+  if (param_type.empty()) {
+    return false;
+  }
+  s << param_type << " " << GetName();
+  return true;
+}
+
+bool PacketField::BuilderParameterMustBeMoved() const {
+  return false;
 }
 
 bool PacketField::GenBuilderMember(std::ostream& s) const {
   return GenBuilderParameter(s);
 }
+
+void PacketField::GenBuilderParameterFromView(std::ostream& s) const {
+  s << "view.Get" << util::UnderscoreToCamelCase(GetName()) << "()";
+}
+
+bool PacketField::IsContainerField() const {
+  return false;
+}
+
+const PacketField* PacketField::GetElementField() const {
+  return nullptr;
+}
diff --git a/gd/packet/parser/fields/packet_field.h b/gd/packet/parser/fields/packet_field.h
index 03e6294..d369a92 100644
--- a/gd/packet/parser/fields/packet_field.h
+++ b/gd/packet/parser/fields/packet_field.h
@@ -40,15 +40,22 @@
   // For most field types, this will be the same as GetSize();
   virtual Size GetBuilderSize() const;
 
+  // Returns the size of the field in bits given the information in the parsed struct.
+  // For most field types, this will be the same as GetSize();
+  virtual Size GetStructSize() const;
+
   // Get the type of the field to be used in the builders constructor and
   // variables.
   virtual std::string GetDataType() const = 0;
 
-  // Given an iterator it, extract the type.
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const = 0;
+  // Given an iterator {name}_it, extract the type.
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const = 0;
 
-  // Calculate field_begin and field_end using the given offsets and size.
-  virtual void GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size field_size) const;
+  // Calculate field_begin and field_end using the given offsets and size, return the number of leading bits
+  virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const;
+
+  // Get the name of the getter function, return empty string if there is a getter function
+  virtual std::string GetGetterFunctionName() const = 0;
 
   // Get parser getter definition. Start_offset points to the first bit of the
   // field. end_offset is the first bit after the field. If an offset is empty
@@ -56,12 +63,21 @@
   // calculate the offset.
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const = 0;
 
+  // Get the type of parameter used in Create(), return empty string if a parameter type was NOT generated
+  virtual std::string GetBuilderParameterType() const = 0;
+
   // Generate the parameter for Create(), return true if a parameter was added.
-  virtual bool GenBuilderParameter(std::ostream& s) const = 0;
+  virtual bool GenBuilderParameter(std::ostream& s) const;
+
+  // Return true if the Builder parameter has to be moved.
+  virtual bool BuilderParameterMustBeMoved() const;
 
   // Generate the actual storage for the parameter, return true if it was added.
   virtual bool GenBuilderMember(std::ostream& s) const;
 
+  // Helper for reflection tests.
+  virtual void GenBuilderParameterFromView(std::ostream& s) const;
+
   // Returns whether or not the field must be validated.
   virtual bool HasParameterValidator() const = 0;
 
@@ -84,6 +100,13 @@
   // see if they contain the correct value.
   virtual void GenValidator(std::ostream& s) const = 0;
 
+  // Some fields are containers of other fields, e.g. array, vector, etc.
+  // Assume STL containers that support swap()
+  virtual bool IsContainerField() const;
+
+  // Get field of nested elements if this is a container field, nullptr if none
+  virtual const PacketField* GetElementField() const;
+
   std::string GetDebugName() const override;
 
   ParseLocation GetLocation() const override;
diff --git a/gd/packet/parser/fields/padding_field.cc b/gd/packet/parser/fields/padding_field.cc
new file mode 100644
index 0000000..5f438f8
--- /dev/null
+++ b/gd/packet/parser/fields/padding_field.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 "fields/padding_field.h"
+#include "util.h"
+
+const std::string PaddingField::kFieldType = "PaddingField";
+
+PaddingField::PaddingField(int size, ParseLocation loc)
+    : PacketField("padding_" + std::to_string(size * 8), loc), size_(size * 8) {}
+
+const std::string& PaddingField::GetFieldType() const {
+  return PaddingField::kFieldType;
+}
+
+Size PaddingField::GetSize() const {
+  return size_;
+}
+
+Size PaddingField::GetBuilderSize() const {
+  return 0;
+}
+
+std::string PaddingField::GetDataType() const {
+  return "There's no type for Padding fields";
+}
+
+void PaddingField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string PaddingField::GetGetterFunctionName() const {
+  return "";
+}
+
+void PaddingField::GenGetter(std::ostream&, Size, Size) const {}
+
+std::string PaddingField::GetBuilderParameterType() const {
+  return "";
+}
+
+bool PaddingField::HasParameterValidator() const {
+  return false;
+}
+
+void PaddingField::GenParameterValidator(std::ostream&) const {}
+
+void PaddingField::GenInserter(std::ostream&) const {
+  ERROR(this) << __func__ << ": This should not be called for padding fields";
+}
+
+void PaddingField::GenValidator(std::ostream&) const {}
diff --git a/gd/packet/parser/fields/padding_field.h b/gd/packet/parser/fields/padding_field.h
new file mode 100644
index 0000000..bb99d42
--- /dev/null
+++ b/gd/packet/parser/fields/padding_field.h
@@ -0,0 +1,56 @@
+/*
+ * 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class PaddingField : public PacketField {
+ public:
+  PaddingField(int size, ParseLocation loc);
+
+  static const std::string kFieldType;
+
+  std::string GetField() const;
+
+  virtual const std::string& GetFieldType() const override;
+
+  virtual Size GetSize() const override;
+
+  virtual Size GetBuilderSize() const override;
+
+  virtual std::string GetDataType() const override;
+
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
+
+  virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+  virtual std::string GetBuilderParameterType() const override;
+
+  virtual bool HasParameterValidator() const override;
+
+  virtual void GenParameterValidator(std::ostream&) const override;
+
+  virtual void GenInserter(std::ostream&) const override;
+
+  virtual void GenValidator(std::ostream&) const override;
+
+ private:
+  Size size_;
+};
diff --git a/gd/packet/parser/fields/payload_field.cc b/gd/packet/parser/fields/payload_field.cc
index ad79032..c075996 100644
--- a/gd/packet/parser/fields/payload_field.cc
+++ b/gd/packet/parser/fields/payload_field.cc
@@ -54,31 +54,44 @@
   return "PacketView";
 }
 
-void PayloadField::GenExtractor(std::ostream&, Size, Size) const {
+void PayloadField::GenExtractor(std::ostream&, int, bool) const {
   ERROR(this) << __func__ << " should never be called. ";
 }
 
+std::string PayloadField::GetGetterFunctionName() const {
+  return "GetPayload";
+}
+
 void PayloadField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  s << "PacketView<kLittleEndian> GetPayload() const {";
+  s << "PacketView<kLittleEndian> " << GetGetterFunctionName() << "() const {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
+  s << "auto to_bound = begin();";
   GenBounds(s, start_offset, end_offset, GetSize());
   s << "return GetLittleEndianSubview(field_begin, field_end);";
   s << "}\n\n";
 
-  s << "PacketView<!kLittleEndian> GetPayloadBigEndian() const {";
+  s << "PacketView<!kLittleEndian> " << GetGetterFunctionName() << "BigEndian() const {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
+  s << "auto to_bound = begin();";
   GenBounds(s, start_offset, end_offset, GetSize());
   s << "return GetBigEndianSubview(field_begin, field_end);";
   s << "}\n";
 }
 
-bool PayloadField::GenBuilderParameter(std::ostream& s) const {
-  s << "std::unique_ptr<BasePacketBuilder> payload";
+std::string PayloadField::GetBuilderParameterType() const {
+  return "std::unique_ptr<BasePacketBuilder>";
+}
+
+bool PayloadField::BuilderParameterMustBeMoved() const {
   return true;
 }
 
+void PayloadField::GenBuilderParameterFromView(std::ostream& s) const {
+  s << "std::make_unique<RawBuilder>(std::vector<uint8_t>(view.GetPayload().begin(), view.GetPayload().end()))";
+}
+
 bool PayloadField::HasParameterValidator() const {
   return false;
 }
diff --git a/gd/packet/parser/fields/payload_field.h b/gd/packet/parser/fields/payload_field.h
index 04fd364..11e6267 100644
--- a/gd/packet/parser/fields/payload_field.h
+++ b/gd/packet/parser/fields/payload_field.h
@@ -34,11 +34,17 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
+
+  virtual bool BuilderParameterMustBeMoved() const override;
+
+  virtual void GenBuilderParameterFromView(std::ostream& s) const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/reserved_field.cc b/gd/packet/parser/fields/reserved_field.cc
index 51f9d84..0acf7b7 100644
--- a/gd/packet/parser/fields/reserved_field.cc
+++ b/gd/packet/parser/fields/reserved_field.cc
@@ -36,15 +36,19 @@
   return util::GetTypeForSize(size_);
 }
 
-void ReservedField::GenExtractor(std::ostream&, Size, Size) const {}
+void ReservedField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ReservedField::GetGetterFunctionName() const {
+  return "";
+}
 
 void ReservedField::GenGetter(std::ostream&, Size, Size) const {
   // There is no Getter for a reserved field
 }
 
-bool ReservedField::GenBuilderParameter(std::ostream&) const {
+std::string ReservedField::GetBuilderParameterType() const {
   // There is no builder parameter for a reserved field
-  return false;
+  return "";
 }
 
 bool ReservedField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/reserved_field.h b/gd/packet/parser/fields/reserved_field.h
index 6c5e160..7d36352 100644
--- a/gd/packet/parser/fields/reserved_field.h
+++ b/gd/packet/parser/fields/reserved_field.h
@@ -31,11 +31,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream&, Size, Size) const override;
 
-  virtual bool GenBuilderParameter(std::ostream&) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
diff --git a/gd/packet/parser/fields/scalar_field.cc b/gd/packet/parser/fields/scalar_field.cc
index bd9ee1b..c6d2ecf 100644
--- a/gd/packet/parser/fields/scalar_field.cc
+++ b/gd/packet/parser/fields/scalar_field.cc
@@ -47,64 +47,67 @@
   }
 }
 
-void ScalarField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
+int ScalarField::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
   int num_leading_bits = 0;
-  int field_size = GetSize().bits();
 
   if (!start_offset.empty()) {
     // Default to start if available.
     num_leading_bits = start_offset.bits() % 8;
-    s << "auto it = begin_it + (" << start_offset << ") / 8;";
+    s << "auto " << GetName() << "_it = to_bound + (" << start_offset << ") / 8;";
   } else if (!end_offset.empty()) {
-    num_leading_bits = GetShiftBits(end_offset.bits() + field_size);
-    Size byte_offset = Size(num_leading_bits + field_size) + end_offset;
-    s << "auto it = end_it - (" << byte_offset << ") / 8;";
+    num_leading_bits = GetShiftBits(end_offset.bits() + size.bits());
+    Size byte_offset = Size(num_leading_bits + size.bits()) + end_offset;
+    s << "auto " << GetName() << "_it = to_bound + (to_bound.NumBytesRemaining() - (" << byte_offset << ") / 8);";
   } else {
     ERROR(this) << "Ambiguous offset for field.";
   }
+  return num_leading_bits;
+}
 
+void ScalarField::GenExtractor(std::ostream& s, int num_leading_bits, bool) const {
+  Size size = GetSize();
   // Extract the correct number of bytes. The return type could be different
   // from the extract type if an earlier field causes the beginning of the
   // current field to start in the middle of a byte.
-  std::string extract_type = util::GetTypeForSize(field_size + num_leading_bits);
-  s << "auto extracted_value = it.extract<" << extract_type << ">();";
+  std::string extract_type = util::GetTypeForSize(size.bits() + num_leading_bits);
+  s << "auto extracted_value = " << GetName() << "_it.extract<" << extract_type << ">();";
 
   // Right shift the result to remove leading bits.
   if (num_leading_bits != 0) {
     s << "extracted_value >>= " << num_leading_bits << ";";
   }
-
   // Mask the result if necessary.
-  if (util::RoundSizeUp(field_size) != field_size) {
+  if (util::RoundSizeUp(size.bits()) != size.bits()) {
     uint64_t mask = 0;
-    for (int i = 0; i < field_size; i++) {
+    for (int i = 0; i < size.bits(); i++) {
       mask <<= 1;
       mask |= 1;
     }
     s << "extracted_value &= 0x" << std::hex << mask << std::dec << ";";
   }
-  s << GetDataType() << " value = static_cast<" << GetDataType() << ">(extracted_value);";
+  s << "*" << GetName() << "_ptr = static_cast<" << GetDataType() << ">(extracted_value);";
+}
+
+std::string ScalarField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
 }
 
 void ScalarField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  s << GetDataType();
-  s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
+  s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
   s << "ASSERT(was_validated_);";
-
-  if (!start_offset.empty()) {
-    s << "auto begin_it = begin();";
-  } else {
-    s << "auto end_it = end();";
-  }
-  GenExtractor(s, start_offset, end_offset);
-  s << "\n";
-  s << "return value;";
+  s << "auto to_bound = begin();";
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << GetDataType() << " " << GetName() << "_value;";
+  s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+  GenExtractor(s, num_leading_bits, false);
+  s << "return " << GetName() << "_value;";
   s << "}";
 }
 
-bool ScalarField::GenBuilderParameter(std::ostream& s) const {
-  s << GetDataType() << " " << GetName();
-  return true;
+std::string ScalarField::GetBuilderParameterType() const {
+  return GetDataType();
 }
 
 bool ScalarField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/scalar_field.h b/gd/packet/parser/fields/scalar_field.h
index b51c43c..65f897e 100644
--- a/gd/packet/parser/fields/scalar_field.h
+++ b/gd/packet/parser/fields/scalar_field.h
@@ -31,11 +31,15 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const override;
+
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
@@ -46,5 +50,5 @@
   virtual void GenValidator(std::ostream&) const override;
 
  private:
-  int size_;
+  const int size_;
 };
diff --git a/gd/packet/parser/fields/struct_field.cc b/gd/packet/parser/fields/struct_field.cc
index d0cb840..fbdafcf 100644
--- a/gd/packet/parser/fields/struct_field.cc
+++ b/gd/packet/parser/fields/struct_field.cc
@@ -19,7 +19,7 @@
 
 const std::string StructField::kFieldType = "StructField";
 
-StructField::StructField(std::string name, std::string type_name, int size, ParseLocation loc)
+StructField::StructField(std::string name, std::string type_name, Size size, ParseLocation loc)
     : PacketField(name, loc), type_name_(type_name), size_(size) {}
 
 const std::string& StructField::GetFieldType() const {
@@ -31,51 +31,41 @@
 }
 
 Size StructField::GetBuilderSize() const {
-  if (size_ != -1) {
-    return size_;
-  } else {
-    std::string ret = "(" + GetName() + "_.size() * 8) ";
-    return ret;
-  }
+  std::string ret = "(" + GetName() + "_.size() * 8)";
+  return ret;
 }
 
 std::string StructField::GetDataType() const {
   return type_name_;
 }
 
-void StructField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
-  if (size_ != -1) {
-    GenBounds(s, start_offset, end_offset, Size(size_));
-  } else {
-    GenBounds(s, start_offset, end_offset, Size());
-  }
-  s << " auto subview = GetLittleEndianSubview(field_begin, field_end); ";
-  s << "auto it = subview.begin();";
-  s << "std::vector<" << GetDataType() << "> vec;";
-  s << GetDataType() << "::Parse(vec, it);";
+void StructField::GenExtractor(std::ostream& s, int, bool) const {
+  s << GetName() << "_it = ";
+  s << GetDataType() << "::Parse(" << GetName() << "_ptr, " << GetName() << "_it);";
+}
+
+std::string StructField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
 }
 
 void StructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  if (size_ != -1) {
-    s << GetDataType() << " Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
-  } else {
-    s << "std::vector<" << GetDataType() << "> Get" << util::UnderscoreToCamelCase(GetName()) << "() const {";
-  }
+  s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
-  GenExtractor(s, start_offset, end_offset);
+  s << "auto to_bound = begin();";
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << GetDataType() << " " << GetName() << "_value;";
+  s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+  GenExtractor(s, num_leading_bits, false);
 
-  if (size_ != -1) {
-    s << "return vec[0];";
-  } else {
-    s << "return vec;";
-  }
+  s << "return " << GetName() << "_value;";
   s << "}\n";
 }
 
-bool StructField::GenBuilderParameter(std::ostream& s) const {
-  s << GetDataType() << " " << GetName();
-  return true;
+std::string StructField::GetBuilderParameterType() const {
+  return GetDataType();
 }
 
 bool StructField::HasParameterValidator() const {
diff --git a/gd/packet/parser/fields/struct_field.h b/gd/packet/parser/fields/struct_field.h
index 3577b1d..1f4f100 100644
--- a/gd/packet/parser/fields/struct_field.h
+++ b/gd/packet/parser/fields/struct_field.h
@@ -21,7 +21,7 @@
 
 class StructField : public PacketField {
  public:
-  StructField(std::string name, std::string type_name, int size, ParseLocation loc);
+  StructField(std::string name, std::string type_name, Size size, ParseLocation loc);
 
   static const std::string kFieldType;
 
@@ -33,11 +33,13 @@
 
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
 
   virtual bool HasParameterValidator() const override;
 
@@ -51,5 +53,5 @@
   std::string type_name_;
 
  public:
-  const int size_{-1};
+  const Size size_{};
 };
diff --git a/gd/packet/parser/fields/variable_length_struct_field.cc b/gd/packet/parser/fields/variable_length_struct_field.cc
new file mode 100644
index 0000000..51a46e4
--- /dev/null
+++ b/gd/packet/parser/fields/variable_length_struct_field.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "fields/variable_length_struct_field.h"
+#include "util.h"
+
+const std::string VariableLengthStructField::kFieldType = "VariableLengthStructField";
+
+VariableLengthStructField::VariableLengthStructField(std::string name, std::string type_name, ParseLocation loc)
+    : PacketField(name, loc), type_name_(type_name) {}
+
+const std::string& VariableLengthStructField::GetFieldType() const {
+  return VariableLengthStructField::kFieldType;
+}
+
+Size VariableLengthStructField::GetSize() const {
+  return Size();
+}
+
+Size VariableLengthStructField::GetBuilderSize() const {
+  std::string ret = "(" + GetName() + "_->size() * 8) ";
+  return ret;
+}
+
+std::string VariableLengthStructField::GetDataType() const {
+  std::string ret = "std::unique_ptr<" + type_name_ + ">";
+  return ret;
+}
+
+void VariableLengthStructField::GenExtractor(std::ostream& s, int, bool) const {
+  s << GetName() << "_ptr = Parse" << type_name_ << "(" << GetName() << "_it);";
+  s << "if (" << GetName() << "_ptr != nullptr) {";
+  s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_ptr->size();";
+  s << "} else {";
+  s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_it.NumBytesRemaining();";
+  s << "}";
+}
+
+std::string VariableLengthStructField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
+}
+
+void VariableLengthStructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+  s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
+  s << "ASSERT(was_validated_);";
+  s << "size_t end_index = size();";
+  s << "auto to_bound = begin();";
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << "std::unique_ptr<" << type_name_ << "> " << GetName() << "_ptr;";
+  GenExtractor(s, num_leading_bits, false);
+  s << "return " << GetName() << "_ptr;";
+  s << "}\n";
+}
+
+std::string VariableLengthStructField::GetBuilderParameterType() const {
+  return GetDataType();
+}
+
+bool VariableLengthStructField::BuilderParameterMustBeMoved() const {
+  return true;
+}
+
+bool VariableLengthStructField::HasParameterValidator() const {
+  return false;
+}
+
+void VariableLengthStructField::GenParameterValidator(std::ostream&) const {
+  // Validated at compile time.
+}
+
+void VariableLengthStructField::GenInserter(std::ostream& s) const {
+  s << GetName() << "_->Serialize(i);";
+}
+
+void VariableLengthStructField::GenValidator(std::ostream&) const {
+  // Do nothing
+}
diff --git a/gd/packet/parser/fields/variable_length_struct_field.h b/gd/packet/parser/fields/variable_length_struct_field.h
new file mode 100644
index 0000000..0b1b97f
--- /dev/null
+++ b/gd/packet/parser/fields/variable_length_struct_field.h
@@ -0,0 +1,56 @@
+/*
+ * 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 "fields/packet_field.h"
+#include "parse_location.h"
+
+class VariableLengthStructField : public PacketField {
+ public:
+  VariableLengthStructField(std::string name, std::string type_name, ParseLocation loc);
+
+  static const std::string kFieldType;
+
+  virtual const std::string& GetFieldType() const override;
+
+  virtual Size GetSize() const override;
+
+  virtual Size GetBuilderSize() const override;
+
+  virtual std::string GetDataType() const override;
+
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
+
+  virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+  virtual std::string GetBuilderParameterType() const override;
+
+  virtual bool BuilderParameterMustBeMoved() const override;
+
+  virtual bool HasParameterValidator() const override;
+
+  virtual void GenParameterValidator(std::ostream&) const override;
+
+  virtual void GenInserter(std::ostream& s) const override;
+
+  virtual void GenValidator(std::ostream&) const override;
+
+ private:
+  std::string type_name_;
+};
diff --git a/gd/packet/parser/fields/vector_field.cc b/gd/packet/parser/fields/vector_field.cc
index b43e36a..ab47c4f 100644
--- a/gd/packet/parser/fields/vector_field.cc
+++ b/gd/packet/parser/fields/vector_field.cc
@@ -15,25 +15,28 @@
  */
 
 #include "fields/vector_field.h"
+
+#include "fields/count_field.h"
+#include "fields/custom_field.h"
 #include "util.h"
 
 const std::string VectorField::kFieldType = "VectorField";
 
 VectorField::VectorField(std::string name, int element_size, std::string size_modifier, ParseLocation loc)
-    : PacketField(name, loc), element_size_(element_size), size_modifier_(size_modifier) {
-  if (element_size_ > 64 || element_size_ < 0)
-    ERROR(this) << __func__ << ": Not implemented for element size = " << element_size_;
-  // Make sure the element_size is a multiple of 8.
+    : PacketField(name, loc), element_field_(new ScalarField("val", element_size, loc)), element_size_(element_size),
+      size_modifier_(size_modifier) {
+  if (element_size > 64 || element_size < 0)
+    ERROR(this) << __func__ << ": Not implemented for element size = " << element_size;
   if (element_size % 8 != 0) {
     ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size << ")";
   }
 }
 
 VectorField::VectorField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc)
-    : PacketField(name, loc), element_size_(type_def->size_), type_def_(type_def), size_modifier_(size_modifier) {
-  // If the element type is not variable sized, make sure that it is byte aligned.
-  if (type_def_->size_ != -1 && type_def_->size_ % 8 != 0) {
-    ERROR(this) << "Can only have arrays with elements that are byte aligned (" << type_def_->size_ << ")";
+    : PacketField(name, loc), element_field_(type_def->GetNewField("val", loc)),
+      element_size_(element_field_->GetSize()), size_modifier_(size_modifier) {
+  if (!element_size_.empty() && element_size_.bits() % 8 != 0) {
+    ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_ << ")";
   }
 }
 
@@ -49,33 +52,27 @@
 
   // size_field_ is of type SIZE
   if (size_field_->GetFieldType() == SizeField::kFieldType) {
-    std::string ret = "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * 8)";
+    std::string ret = "(static_cast<size_t>(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()) * 8)";
     if (!size_modifier_.empty()) ret += size_modifier_;
     return ret;
   }
 
-  // size_field_ is of type COUNT and it is a scalar array
-  if (type_def_ == nullptr) {
-    return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(element_size_) + ")";
+  // size_field_ is of type COUNT and elements have a fixed size
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    return "(static_cast<size_t>(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()) * " +
+           std::to_string(element_size_.bits()) + ")";
   }
 
-  if (IsCustomFieldArray() || IsStructArray()) {
-    if (type_def_->size_ != -1) {
-      return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_) +
-             ")";
-    } else {
-      return Size();
-    }
-  }
-
-  // size_field_ is of type COUNT and it is an enum array
-  return "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * " + std::to_string(type_def_->size_) +
-         ")";
+  return Size();
 }
 
 Size VectorField::GetBuilderSize() const {
-  if (element_size_ != -1) {
-    std::string ret = "(" + GetName() + "_.size() * " + std::to_string(element_size_) + ")";
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    std::string ret = "(static_cast<size_t>(" + GetName() + "_.size()) * " + std::to_string(element_size_.bits()) + ")";
+    return ret;
+  } else if (element_field_->BuilderParameterMustBeMoved()) {
+    std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+                      "_) { length += elem->size() * 8; } return length; }()";
     return ret;
   } else {
     std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
@@ -84,51 +81,106 @@
   }
 }
 
-std::string VectorField::GetDataType() const {
-  if (type_def_ != nullptr) {
-    return "std::vector<" + type_def_->name_ + ">";
+Size VectorField::GetStructSize() const {
+  // If there is no size field, then it is of unknown size.
+  if (size_field_ == nullptr) {
+    return Size();
   }
-  return "std::vector<" + util::GetTypeForSize(element_size_) + ">";
+
+  // size_field_ is of type SIZE
+  if (size_field_->GetFieldType() == SizeField::kFieldType) {
+    std::string ret = "(static_cast<size_t>(" + size_field_->GetName() + "_extracted) * 8)";
+    if (!size_modifier_.empty()) ret += "-" + size_modifier_;
+    return ret;
+  }
+
+  // size_field_ is of type COUNT and elements have a fixed size
+  if (!element_size_.empty() && !element_size_.has_dynamic()) {
+    return "(static_cast<size_t>(" + size_field_->GetName() + "_extracted) * " + std::to_string(element_size_.bits()) +
+           ")";
+  }
+
+  return Size();
 }
 
-void VectorField::GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const {
-  GenBounds(s, start_offset, end_offset, GetSize());
+std::string VectorField::GetDataType() const {
+  return "std::vector<" + element_field_->GetDataType() + ">";
+}
 
-  s << " auto subview = GetLittleEndianSubview(field_begin, field_end); ";
-  s << "auto it = subview.begin();";
-
-  // Add the element size so that we will extract as many elements as we can.
-  s << GetDataType() << " ret;";
-  if (element_size_ != -1) {
-    std::string type = (type_def_ != nullptr) ? type_def_->name_ : util::GetTypeForSize(element_size_);
-    s << "while (it + sizeof(" << type << ") <= subview.end()) {";
-    s << "ret.push_back(it.extract<" << type << ">());";
-    s << "}";
-  } else {
-    s << "while (it < subview.end()) {";
-    s << "it = " << type_def_->name_ << "::Parse(ret, it);";
-    s << "}";
+void VectorField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const {
+  s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;";
+  if (size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType) {
+    s << "size_t " << element_field_->GetName() << "_count = ";
+    if (for_struct) {
+      s << size_field_->GetName() << "_extracted;";
+    } else {
+      s << "Get" << util::UnderscoreToCamelCase(size_field_->GetName()) << "();";
+    }
   }
+  s << "while (";
+  if (size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType) {
+    s << "(" << element_field_->GetName() << "_count-- > 0) && ";
+  }
+  if (!element_size_.empty()) {
+    s << element_field_->GetName() << "_it.NumBytesRemaining() >= " << element_size_.bytes() << ") {";
+  } else {
+    s << element_field_->GetName() << "_it.NumBytesRemaining() > 0) {";
+  }
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;";
+  } else {
+    s << element_field_->GetDataType() << " " << element_field_->GetName() << "_value;";
+    s << element_field_->GetDataType() << "* " << element_field_->GetName() << "_ptr = &" << element_field_->GetName()
+      << "_value;";
+  }
+  element_field_->GenExtractor(s, num_leading_bits, for_struct);
+  s << "if (" << element_field_->GetName() << "_ptr != nullptr) { ";
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    s << GetName() << "_ptr->push_back(std::move(" << element_field_->GetName() << "_ptr));";
+  } else {
+    s << GetName() << "_ptr->push_back(" << element_field_->GetName() << "_value);";
+  }
+  s << "}";
+  s << "}";
+}
+
+std::string VectorField::GetGetterFunctionName() const {
+  std::stringstream ss;
+  ss << "Get" << util::UnderscoreToCamelCase(GetName());
+  return ss.str();
 }
 
 void VectorField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
-  s << GetDataType();
-  s << " Get" << util::UnderscoreToCamelCase(GetName()) << "() {";
+  s << GetDataType() << " " << GetGetterFunctionName() << "() {";
   s << "ASSERT(was_validated_);";
   s << "size_t end_index = size();";
+  s << "auto to_bound = begin();";
 
-  GenExtractor(s, start_offset, end_offset);
+  int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+  s << GetDataType() << " " << GetName() << "_value;";
+  s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+  GenExtractor(s, num_leading_bits, false);
 
-  s << "return ret;";
+  s << "return " << GetName() << "_value;";
   s << "}\n";
 }
 
-bool VectorField::GenBuilderParameter(std::ostream& s) const {
-  if (type_def_ != nullptr) {
-    s << "const std::vector<" << type_def_->GetTypeName() << ">& " << GetName();
+std::string VectorField::GetBuilderParameterType() const {
+  std::stringstream ss;
+  if (element_field_->BuilderParameterMustBeMoved()) {
+    ss << "std::vector<" << element_field_->GetDataType() << ">";
   } else {
-    s << "const std::vector<" << util::GetTypeForSize(element_size_) << ">& " << GetName();
+    ss << "const std::vector<" << element_field_->GetDataType() << ">&";
   }
+  return ss.str();
+}
+
+bool VectorField::BuilderParameterMustBeMoved() const {
+  return element_field_->BuilderParameterMustBeMoved();
+}
+
+bool VectorField::GenBuilderMember(std::ostream& s) const {
+  s << "std::vector<" << element_field_->GetDataType() << "> " << GetName();
   return true;
 }
 
@@ -145,20 +197,8 @@
 }
 
 void VectorField::GenInserter(std::ostream& s) const {
-  s << "for (const auto& val : " << GetName() << "_) {";
-  if (IsEnumArray()) {
-    s << "insert(static_cast<" << util::GetTypeForSize(type_def_->size_) << ">(val), i, " << type_def_->size_ << ");";
-  } else if (IsCustomFieldArray()) {
-    if (type_def_->size_ == -1) {
-      s << "val.Serialize(i);";
-    } else {
-      s << "insert(val, i);";
-    }
-  } else if (IsStructArray()) {
-    s << "val.Serialize(i);";
-  } else {
-    s << "insert(val, i, " << element_size_ << ");";
-  }
+  s << "for (const auto& val_ : " << GetName() << "_) {";
+  element_field_->GenInserter(s);
   s << "}\n";
 }
 
@@ -170,18 +210,6 @@
   // be done here.
 }
 
-bool VectorField::IsEnumArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::ENUM;
-}
-
-bool VectorField::IsCustomFieldArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::CUSTOM;
-}
-
-bool VectorField::IsStructArray() const {
-  return type_def_ != nullptr && type_def_->GetDefinitionType() == TypeDef::Type::STRUCT;
-}
-
 void VectorField::SetSizeField(const SizeField* size_field) {
   if (size_field->GetFieldType() == CountField::kFieldType && !size_modifier_.empty()) {
     ERROR(this, size_field) << "Can not use count field to describe array with a size modifier."
@@ -194,3 +222,11 @@
 const std::string& VectorField::GetSizeModifier() const {
   return size_modifier_;
 }
+
+bool VectorField::IsContainerField() const {
+  return true;
+}
+
+const PacketField* VectorField::GetElementField() const {
+  return element_field_;
+}
diff --git a/gd/packet/parser/fields/vector_field.h b/gd/packet/parser/fields/vector_field.h
index d29759a..b2ae95d 100644
--- a/gd/packet/parser/fields/vector_field.h
+++ b/gd/packet/parser/fields/vector_field.h
@@ -16,12 +16,10 @@
 
 #pragma once
 
-#include "custom_field_def.h"
-#include "enum_def.h"
-#include "fields/count_field.h"
 #include "fields/packet_field.h"
 #include "fields/size_field.h"
 #include "parse_location.h"
+#include "type_def.h"
 
 class VectorField : public PacketField {
  public:
@@ -37,13 +35,21 @@
 
   virtual Size GetBuilderSize() const override;
 
+  virtual Size GetStructSize() const override;
+
   virtual std::string GetDataType() const override;
 
-  virtual void GenExtractor(std::ostream& s, Size start_offset, Size end_offset) const override;
+  virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+  virtual std::string GetGetterFunctionName() const override;
 
   virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
 
-  virtual bool GenBuilderParameter(std::ostream& s) const override;
+  virtual std::string GetBuilderParameterType() const override;
+
+  virtual bool BuilderParameterMustBeMoved() const override;
+
+  virtual bool GenBuilderMember(std::ostream& s) const override;
 
   virtual bool HasParameterValidator() const override;
 
@@ -53,22 +59,21 @@
 
   virtual void GenValidator(std::ostream&) const override;
 
-  bool IsEnumArray() const;
-
-  bool IsCustomFieldArray() const;
-
-  bool IsStructArray() const;
-
   void SetSizeField(const SizeField* size_field);
 
   const std::string& GetSizeModifier() const;
 
+  virtual bool IsContainerField() const override;
+
+  virtual const PacketField* GetElementField() const override;
+
   const std::string name_;
 
-  const int element_size_{-1};  // in bits
-  const TypeDef* type_def_{nullptr};
+  const PacketField* element_field_{nullptr};
 
-  // Fixed size array or dynamic size, size is always in bytes, unless it is count.
+  const Size element_size_{};
+
+  // Size is always in bytes, unless it is a count.
   const SizeField* size_field_{nullptr};
 
   // Size modifier is only used when size_field_ is of type SIZE and is not used with COUNT.
diff --git a/gd/packet/parser/language_l.ll b/gd/packet/parser/language_l.ll
index f653bb0..5814ec1 100644
--- a/gd/packet/parser/language_l.ll
+++ b/gd/packet/parser/language_l.ll
@@ -57,6 +57,7 @@
 "_fixed_"               { return(token::FIXED); }
 "_reserved_"            { return(token::RESERVED); }
 "_checksum_start_"      { return(token::CHECKSUM_START); }
+"_padding_"             { return(token::PADDING); }
   /* Types */
 "checksum"              { return(token::CHECKSUM); }
 "custom_field"          { return(token::CUSTOM_FIELD); }
diff --git a/gd/packet/parser/language_y.yy b/gd/packet/parser/language_y.yy
index 2623ea3..a36abef 100644
--- a/gd/packet/parser/language_y.yy
+++ b/gd/packet/parser/language_y.yy
@@ -69,6 +69,7 @@
 %token CUSTOM_FIELD "custom_field"
 %token CHECKSUM "checksum"
 %token CHECKSUM_START "checksum_start"
+%token PADDING "padding"
 
 %type<enum_definition> enum_definition
 %type<enumeration_values> enumeration_list
@@ -81,6 +82,7 @@
 %type<packet_field_type> type_def_field_definition;
 %type<packet_field_type> scalar_field_definition;
 %type<packet_field_type> checksum_start_field_definition;
+%type<packet_field_type> padding_field_definition;
 %type<packet_field_type> size_field_definition;
 %type<packet_field_type> payload_field_definition;
 %type<packet_field_type> body_field_definition;
@@ -114,18 +116,18 @@
 declaration
   : enum_definition
     {
-      std::cerr << "FOUND ENUM\n\n";
+      DEBUG() << "FOUND ENUM\n\n";
       decls->AddTypeDef($1->name_, $1);
     }
   | packet_definition
     {
-      std::cerr << "FOUND PACKET\n\n";
+      DEBUG() << "FOUND PACKET\n\n";
       decls->AddPacketDef($1->name_, std::move(*$1));
       delete $1;
     }
   | struct_definition
     {
-      std::cerr << "FOUND STRUCT\n\n";
+      DEBUG() << "FOUND STRUCT\n\n";
       decls->AddTypeDef($1->name_, $1);
     }
   | group_definition
@@ -144,7 +146,7 @@
 enum_definition
   : ENUM IDENTIFIER ':' INTEGER '{' enumeration_list ',' '}'
     {
-      std::cerr << "Enum Declared: name=" << *$2
+      DEBUG() << "Enum Declared: name=" << *$2
                 << " size=" << $4 << "\n";
 
       $$ = new EnumDef(std::move(*$2), $4);
@@ -158,14 +160,14 @@
 enumeration_list
   : enumeration
     {
-      std::cerr << "Enumerator with comma\n";
+      DEBUG() << "Enumerator with comma\n";
       $$ = new std::map<int, std::string>();
       $$->insert(std::move(*$1));
       delete $1;
     }
   | enumeration_list ',' enumeration
     {
-      std::cerr << "Enumerator with list\n";
+      DEBUG() << "Enumerator with list\n";
       $$ = $1;
       $$->insert(std::move(*$3));
       delete $3;
@@ -174,7 +176,7 @@
 enumeration
   : IDENTIFIER '=' INTEGER
     {
-      std::cerr << "Enumerator: name=" << *$1
+      DEBUG() << "Enumerator: name=" << *$1
                 << " value=" << $3 << "\n";
       $$ = new std::pair($3, std::move(*$1));
       delete $1;
@@ -190,7 +192,7 @@
 checksum_definition
   : CHECKSUM IDENTIFIER ':' INTEGER STRING
     {
-      std::cerr << "Checksum field defined\n";
+      DEBUG() << "Checksum field defined\n";
       decls->AddTypeDef(*$2, new ChecksumDef(*$2, *$5, $4));
       delete $2;
       delete $5;
@@ -231,8 +233,8 @@
       auto&& parent_struct_name = *$4;
       auto&& field_definition_list = *$6;
 
-      std::cerr << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
-      std::cerr << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+      DEBUG() << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
+      DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
 
       auto parent_struct = decls->GetTypeDef(parent_struct_name);
       if (parent_struct == nullptr) {
@@ -362,12 +364,12 @@
 field_definition_list
   : /* empty */
     {
-      std::cerr << "Empty Field definition\n";
+      DEBUG() << "Empty Field definition\n";
       $$ = new FieldList();
     }
   | field_definition
     {
-      std::cerr << "Field definition\n";
+      DEBUG() << "Field definition\n";
       $$ = new FieldList();
 
       if ($1->GetFieldType() == GroupField::kFieldType) {
@@ -384,7 +386,7 @@
     }
   | field_definition ',' field_definition_list
     {
-      std::cerr << "Field definition with list\n";
+      DEBUG() << "Field definition with list\n";
       $$ = $3;
 
       if ($1->GetFieldType() == GroupField::kFieldType) {
@@ -408,47 +410,52 @@
     }
   | type_def_field_definition
     {
-      std::cerr << "Field with a pre-defined type\n";
+      DEBUG() << "Field with a pre-defined type\n";
       $$ = $1;
     }
   | scalar_field_definition
     {
-      std::cerr << "Scalar field\n";
+      DEBUG() << "Scalar field\n";
       $$ = $1;
     }
   | checksum_start_field_definition
     {
-      std::cerr << "Checksum start field\n";
+      DEBUG() << "Checksum start field\n";
+      $$ = $1;
+    }
+  | padding_field_definition
+    {
+      DEBUG() << "Padding field\n";
       $$ = $1;
     }
   | size_field_definition
     {
-      std::cerr << "Size field\n";
+      DEBUG() << "Size field\n";
       $$ = $1;
     }
   | body_field_definition
     {
-      std::cerr << "Body field\n";
+      DEBUG() << "Body field\n";
       $$ = $1;
     }
   | payload_field_definition
     {
-      std::cerr << "Payload field\n";
+      DEBUG() << "Payload field\n";
       $$ = $1;
     }
   | fixed_field_definition
     {
-      std::cerr << "Fixed field\n";
+      DEBUG() << "Fixed field\n";
       $$ = $1;
     }
   | reserved_field_definition
     {
-      std::cerr << "Reserved field\n";
+      DEBUG() << "Reserved field\n";
       $$ = $1;
     }
   | array_field_definition
     {
-      std::cerr << "ARRAY field\n";
+      DEBUG() << "ARRAY field\n";
       $$ = $1;
     }
 
@@ -467,7 +474,7 @@
     }
   | IDENTIFIER '{' constraint_list '}'
     {
-      std::cerr << "Group with fixed field(s) " << *$1 << "\n";
+      DEBUG() << "Group with fixed field(s) " << *$1 << "\n";
       auto group = decls->GetGroupDef(*$1);
       if (group == nullptr) {
         ERRORLOC(LOC) << "Could not find group with name " << *$1;
@@ -478,10 +485,10 @@
         const auto constraint = $3->find(field->GetName());
         if (constraint != $3->end()) {
           if (field->GetFieldType() == ScalarField::kFieldType) {
-            std::cerr << "Fixing group scalar value\n";
+            DEBUG() << "Fixing group scalar value\n";
             expanded_fields->push_back(new FixedScalarField(field->GetSize().bits(), std::get<int64_t>(constraint->second), LOC));
           } else if (field->GetFieldType() == EnumField::kFieldType) {
-            std::cerr << "Fixing group enum value\n";
+            DEBUG() << "Fixing group enum value\n";
 
             auto type_def = decls->GetTypeDef(field->GetDataType());
             EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
@@ -513,14 +520,14 @@
 constraint_list
   : constraint ',' constraint_list
     {
-      std::cerr << "Group field value list\n";
+      DEBUG() << "Group field value list\n";
       $3->insert(*$1);
       $$ = $3;
       delete($1);
     }
   | constraint
     {
-      std::cerr << "Group field value\n";
+      DEBUG() << "Group field value\n";
       $$ = new std::map<std::string, std::variant<int64_t, std::string>>();
       $$->insert(*$1);
       delete($1);
@@ -529,7 +536,7 @@
 constraint
   : IDENTIFIER '=' INTEGER
     {
-      std::cerr << "Group with a fixed integer value=" << $1 << " value=" << $3 << "\n";
+      DEBUG() << "Group with a fixed integer value=" << $1 << " value=" << $3 << "\n";
 
       $$ = new std::pair(*$1, std::variant<int64_t,std::string>($3));
       delete $1;
@@ -546,7 +553,7 @@
 type_def_field_definition
   : IDENTIFIER ':' IDENTIFIER
     {
-      std::cerr << "Predefined type field " << *$1 << " : " << *$3 << "\n";
+      DEBUG() << "Predefined type field " << *$1 << " : " << *$3 << "\n";
       if (auto type_def = decls->GetTypeDef(*$3)) {
         $$ = type_def->GetNewField(*$1, LOC);
       } else {
@@ -559,7 +566,7 @@
 scalar_field_definition
   : IDENTIFIER ':' INTEGER
     {
-      std::cerr << "Scalar field " << *$1 << " : " << $3 << "\n";
+      DEBUG() << "Scalar field " << *$1 << " : " << $3 << "\n";
       $$ = new ScalarField(*$1, $3, LOC);
       delete $1;
     }
@@ -567,46 +574,53 @@
 body_field_definition
   : BODY
     {
-      std::cerr << "Body field\n";
+      DEBUG() << "Body field\n";
       $$ = new BodyField(LOC);
     }
 
 payload_field_definition
   : PAYLOAD ':' '[' SIZE_MODIFIER ']'
     {
-      std::cerr << "Payload field with modifier " << *$4 << "\n";
+      DEBUG() << "Payload field with modifier " << *$4 << "\n";
       $$ = new PayloadField(*$4, LOC);
       delete $4;
     }
   | PAYLOAD
     {
-      std::cerr << "Payload field\n";
+      DEBUG() << "Payload field\n";
       $$ = new PayloadField("", LOC);
     }
 
 checksum_start_field_definition
   : CHECKSUM_START '(' IDENTIFIER ')'
     {
-      std::cerr << "ChecksumStart field defined\n";
+      DEBUG() << "ChecksumStart field defined\n";
       $$ = new ChecksumStartField(*$3, LOC);
       delete $3;
     }
 
+padding_field_definition
+  : PADDING '[' INTEGER ']'
+    {
+      DEBUG() << "Padding field defined\n";
+      $$ = new PaddingField($3, LOC);
+    }
+
 size_field_definition
   : SIZE '(' IDENTIFIER ')' ':' INTEGER
     {
-      std::cerr << "Size field defined\n";
+      DEBUG() << "Size field defined\n";
       $$ = new SizeField(*$3, $6, LOC);
       delete $3;
     }
   | SIZE '(' PAYLOAD ')' ':' INTEGER
     {
-      std::cerr << "Size for payload defined\n";
+      DEBUG() << "Size for payload defined\n";
       $$ = new SizeField("payload", $6, LOC);
     }
   | COUNT '(' IDENTIFIER ')' ':' INTEGER
     {
-      std::cerr << "Count field defined\n";
+      DEBUG() << "Count field defined\n";
       $$ = new CountField(*$3, $6, LOC);
       delete $3;
     }
@@ -614,7 +628,7 @@
 fixed_field_definition
   : FIXED '=' INTEGER ':' INTEGER
     {
-      std::cerr << "Fixed field defined value=" << $3 << " size=" << $5 << "\n";
+      DEBUG() << "Fixed field defined value=" << $3 << " size=" << $5 << "\n";
       $$ = new FixedScalarField($5, $3, LOC);
     }
   | FIXED '=' IDENTIFIER ':' IDENTIFIER
@@ -639,7 +653,7 @@
 reserved_field_definition
   : RESERVED ':' INTEGER
     {
-      std::cerr << "Reserved field of size=" << $3 << "\n";
+      DEBUG() << "Reserved field of size=" << $3 << "\n";
       $$ = new ReservedField($3, LOC);
     }
 
@@ -706,6 +720,6 @@
 
 
 void yy::parser::error(const yy::parser::location_type& loc, const std::string& error) {
-  std::cerr << error << " at location " << loc << "\n";
+  ERROR() << error << " at location " << loc << "\n";
   abort();
 }
diff --git a/gd/packet/parser/logging.h b/gd/packet/parser/logging.h
index 8d9e467..a2939ef 100644
--- a/gd/packet/parser/logging.h
+++ b/gd/packet/parser/logging.h
@@ -58,6 +58,8 @@
   }
 
   ~LogMessage() {
+    if (debug_ && suppress_debug_) return;
+
     std::cerr << stream_.str() << "\n";
     for (const auto& token : tokens_) {
       // Bold line number
@@ -79,6 +81,7 @@
  private:
   std::ostringstream stream_;
   bool debug_;
+  bool suppress_debug_{true};
   ParseLocation loc_;
   std::vector<const Loggable*> tokens_;
 };
diff --git a/gd/packet/parser/main.cc b/gd/packet/parser/main.cc
index 6f51edd..757523d 100644
--- a/gd/packet/parser/main.cc
+++ b/gd/packet/parser/main.cc
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <errno.h>
 #include <unistd.h>
+#include <cerrno>
 #include <cstdio>
 #include <filesystem>
 #include <fstream>
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include "declarations.h"
+#include "struct_parser_generator.h"
 
 #include "language_y.h"
 
@@ -36,22 +37,21 @@
 
 namespace {
 
-const std::string kBluetoothTopNamespace = "bluetooth";
-
-void parse_namespace(std::filesystem::path input_file_relative_path, std::vector<std::string>& token) {
-  std::filesystem::path gen_namespace = kBluetoothTopNamespace / input_file_relative_path;
+void parse_namespace(const std::string& root_namespace, const std::filesystem::path& input_file_relative_path,
+                     std::vector<std::string>* token) {
+  std::filesystem::path gen_namespace = root_namespace / input_file_relative_path;
   std::string gen_namespace_str = gen_namespace;
   std::regex path_tokenizer("/");
   auto it = std::sregex_token_iterator(gen_namespace_str.cbegin(), gen_namespace_str.cend(), path_tokenizer, -1);
-  std::sregex_token_iterator it_end;
+  std::sregex_token_iterator it_end = {};
   for (; it != it_end; ++it) {
-    token.push_back(it->str());
+    token->push_back(it->str());
   }
 }
 
 void generate_namespace_open(const std::vector<std::string>& token, std::ostream& output) {
-  for (auto it = token.begin(); it != token.end(); ++it) {
-    output << "namespace " << *it << " {" << std::endl;
+  for (const auto& ns : token) {
+    output << "namespace " << ns << " {" << std::endl;
   }
 }
 
@@ -61,17 +61,7 @@
   }
 }
 
-bool parse_one_file(std::filesystem::path input_file, std::filesystem::path include_dir,
-                    std::filesystem::path out_dir) {
-  auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
-
-  auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
-  auto gen_path = out_dir / gen_relative_path;
-
-  std::filesystem::create_directories(gen_path);
-
-  auto gen_file = gen_path / (input_filename + ".h");
-
+bool parse_declarations_one_file(const std::filesystem::path& input_file, Declarations* declarations) {
   void* scanner;
   yylex_init(&scanner);
 
@@ -83,6 +73,43 @@
 
   yyset_in(in_file, scanner);
 
+  int ret = yy::parser(scanner, declarations).parse();
+  if (ret != 0) {
+    std::cerr << "yylex parsing failed: returned " << ret << std::endl;
+    return false;
+  }
+
+  yylex_destroy(scanner);
+
+  fclose(in_file);
+
+  // Set endianess before returning
+  for (auto& s : declarations->type_defs_queue_) {
+    if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+      auto* struct_def = dynamic_cast<StructDef*>(s.second);
+      struct_def->SetEndianness(declarations->is_little_endian);
+    }
+  }
+
+  for (auto& packet_def : declarations->packet_defs_queue_) {
+    packet_def.second.SetEndianness(declarations->is_little_endian);
+  }
+
+  return true;
+}
+
+bool generate_cpp_headers_one_file(const Declarations& decls, const std::filesystem::path& input_file,
+                                   const std::filesystem::path& include_dir, const std::filesystem::path& out_dir,
+                                   const std::string& root_namespace) {
+  auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
+
+  auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
+  auto gen_path = out_dir / gen_relative_path;
+
+  std::filesystem::create_directories(gen_path);
+
+  auto gen_file = gen_path / (input_filename + ".h");
+
   std::ofstream out_file;
   out_file.open(gen_file);
   if (!out_file.is_open()) {
@@ -90,16 +117,6 @@
     return false;
   }
 
-  Declarations decls;
-  int ret = yy::parser(scanner, &decls).parse();
-
-  yylex_destroy(scanner);
-
-  if (ret != 0) {
-    std::cerr << "yylex parsing failed: returned " << ret << std::endl;
-    return false;
-  }
-
   out_file << "\n\n";
   out_file << "#pragma once\n";
   out_file << "\n\n";
@@ -127,7 +144,7 @@
   out_file << "\n\n";
 
   std::vector<std::string> namespace_list;
-  parse_namespace(gen_relative_path, namespace_list);
+  parse_namespace(root_namespace, gen_relative_path, &namespace_list);
   generate_namespace_open(namespace_list, out_file);
   out_file << "\n\n";
 
@@ -152,90 +169,269 @@
 
   for (const auto& e : decls.type_defs_queue_) {
     if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
-      EnumGen gen(*(EnumDef*)e.second);
+      const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+      EnumGen gen(*enum_def);
       gen.GenDefinition(out_file);
       out_file << "\n\n";
     }
   }
   for (const auto& e : decls.type_defs_queue_) {
     if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
-      EnumGen gen(*(EnumDef*)e.second);
+      const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+      EnumGen gen(*enum_def);
       gen.GenLogging(out_file);
       out_file << "\n\n";
     }
   }
   for (const auto& ch : decls.type_defs_queue_) {
     if (ch.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
-      ((ChecksumDef*)ch.second)->GenChecksumCheck(out_file);
+      const auto* checksum_def = dynamic_cast<const ChecksumDef*>(ch.second);
+      checksum_def->GenChecksumCheck(out_file);
     }
   }
   out_file << "\n/* Done ChecksumChecks */\n";
 
   for (const auto& c : decls.type_defs_queue_) {
     if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM && c.second->size_ == -1 /* Variable Size */) {
-      ((CustomFieldDef*)c.second)->GenCustomFieldCheck(out_file);
+      const auto* custom_field_def = dynamic_cast<const CustomFieldDef*>(c.second);
+      custom_field_def->GenCustomFieldCheck(out_file, decls.is_little_endian);
     }
   }
   out_file << "\n";
 
   for (auto& s : decls.type_defs_queue_) {
     if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
-      ((StructDef*)s.second)->SetEndianness(decls.is_little_endian);
-      ((StructDef*)s.second)->GenDefinition(out_file);
+      const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+      struct_def->GenDefinition(out_file);
       out_file << "\n";
     }
   }
 
-  for (size_t i = 0; i < decls.packet_defs_queue_.size(); i++) {
-    decls.packet_defs_queue_[i].second.SetEndianness(decls.is_little_endian);
-    decls.packet_defs_queue_[i].second.GenParserDefinition(out_file);
+  {
+    StructParserGenerator spg(decls);
+    spg.Generate(out_file);
     out_file << "\n\n";
   }
 
-  for (const auto p : decls.packet_defs_queue_) {
-    p.second.GenBuilderDefinition(out_file);
+  for (const auto& packet_def : decls.packet_defs_queue_) {
+    packet_def.second.GenParserDefinition(out_file);
+    out_file << "\n\n";
+  }
+
+  for (const auto& packet_def : decls.packet_defs_queue_) {
+    packet_def.second.GenBuilderDefinition(out_file);
     out_file << "\n\n";
   }
 
   generate_namespace_close(namespace_list, out_file);
 
   out_file.close();
-  fclose(in_file);
+
+  return true;
+}
+
+// Get the out_file shard at a symbol_count
+std::ofstream& get_out_file(size_t symbol_count, size_t symbol_total, std::vector<std::ofstream>* out_files) {
+  auto symbols_per_shard = symbol_total / out_files->size();
+  auto file_index = std::min(symbol_count / symbols_per_shard, out_files->size() - 1);
+  return out_files->at(file_index);
+}
+
+bool generate_pybind11_sources_one_file(const Declarations& decls, const std::filesystem::path& input_file,
+                                        const std::filesystem::path& include_dir, const std::filesystem::path& out_dir,
+                                        const std::string& root_namespace, size_t num_shards) {
+  auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
+
+  auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
+  auto gen_path = out_dir / gen_relative_path;
+
+  std::filesystem::create_directories(gen_path);
+
+  auto gen_relative_header = gen_relative_path / (input_filename + ".h");
+
+  std::vector<std::string> namespace_list;
+  parse_namespace(root_namespace, gen_relative_path, &namespace_list);
+
+  std::vector<std::ofstream> out_file_shards(num_shards);
+  for (size_t i = 0; i < out_file_shards.size(); i++) {
+    auto filename = gen_path / (input_filename + "_python3_shard_" + std::to_string(i) + ".cc");
+    auto& out_file = out_file_shards[i];
+    out_file.open(filename);
+    if (!out_file.is_open()) {
+      std::cerr << "can't open " << filename << std::endl;
+      return false;
+    }
+    out_file << "#include <pybind11/pybind11.h>\n";
+    out_file << "#include <pybind11/stl.h>\n";
+    out_file << "\n\n";
+    out_file << "#include " << gen_relative_header << "\n";
+    out_file << "\n\n";
+
+    generate_namespace_open(namespace_list, out_file);
+    out_file << "\n\n";
+
+    for (const auto& c : decls.type_defs_queue_) {
+      if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM ||
+          c.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+        const auto* custom_def = dynamic_cast<const CustomFieldDef*>(c.second);
+        custom_def->GenUsing(out_file);
+      }
+    }
+    out_file << "\n\n";
+
+    out_file << "using ::bluetooth::packet::BasePacketBuilder;";
+    out_file << "using ::bluetooth::packet::BitInserter;";
+    out_file << "using ::bluetooth::packet::CustomTypeChecker;";
+    out_file << "using ::bluetooth::packet::Iterator;";
+    out_file << "using ::bluetooth::packet::kLittleEndian;";
+    out_file << "using ::bluetooth::packet::PacketBuilder;";
+    out_file << "using ::bluetooth::packet::BaseStruct;";
+    out_file << "using ::bluetooth::packet::PacketStruct;";
+    out_file << "using ::bluetooth::packet::PacketView;";
+    out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
+    out_file << "\n\n";
+
+    out_file << "namespace py = pybind11;\n\n";
+
+    out_file << "void define_" << input_filename << "_submodule_shard_" << std::to_string(i) << "(py::module& m) {\n\n";
+  }
+  size_t symbol_total = 0;
+  // Only count types that will be generated
+  for (const auto& e : decls.type_defs_queue_) {
+    if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+      symbol_total++;
+    } else if (e.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+      symbol_total++;
+    }
+  }
+  // View and builder are counted separately
+  symbol_total += decls.packet_defs_queue_.size() * 2;
+  size_t symbol_count = 0;
+
+  for (const auto& e : decls.type_defs_queue_) {
+    if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+      const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+      EnumGen gen(*enum_def);
+      auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+      gen.GenDefinitionPybind11(out_file);
+      out_file << "\n\n";
+      symbol_count++;
+    }
+  }
+
+  for (const auto& s : decls.type_defs_queue_) {
+    if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+      const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+      auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+      struct_def->GenDefinitionPybind11(out_file);
+      out_file << "\n";
+      symbol_count++;
+    }
+  }
+
+  for (const auto& packet_def : decls.packet_defs_queue_) {
+    auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+    packet_def.second.GenParserDefinitionPybind11(out_file);
+    out_file << "\n\n";
+    symbol_count++;
+  }
+
+  for (const auto& p : decls.packet_defs_queue_) {
+    auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+    p.second.GenBuilderDefinitionPybind11(out_file);
+    out_file << "\n\n";
+    symbol_count++;
+  }
+
+  for (auto& out_file : out_file_shards) {
+    out_file << "}\n\n";
+    generate_namespace_close(namespace_list, out_file);
+  }
+
+  auto gen_file_main = gen_path / (input_filename + "_python3.cc");
+  std::ofstream out_file_main;
+  out_file_main.open(gen_file_main);
+  if (!out_file_main.is_open()) {
+    std::cerr << "can't open " << gen_file_main << std::endl;
+    return false;
+  }
+  out_file_main << "#include <pybind11/pybind11.h>\n";
+  generate_namespace_open(namespace_list, out_file_main);
+
+  out_file_main << "namespace py = pybind11;\n\n";
+
+  for (size_t i = 0; i < out_file_shards.size(); i++) {
+    out_file_main << "void define_" << input_filename << "_submodule_shard_" << std::to_string(i)
+                  << "(py::module& m);\n";
+  }
+
+  out_file_main << "void define_" << input_filename << "_submodule(py::module& parent) {\n\n";
+  out_file_main << "py::module m = parent.def_submodule(\"" << input_filename << "\", \"A submodule of "
+                << input_filename << "\");\n\n";
+  for (size_t i = 0; i < out_file_shards.size(); i++) {
+    out_file_main << "define_" << input_filename << "_submodule_shard_" << std::to_string(i) << "(m);\n";
+  }
+  out_file_main << "}\n\n";
+
+  generate_namespace_close(namespace_list, out_file_main);
 
   return true;
 }
 
 }  // namespace
 
+// TODO(b/141583809): stop leaks
+extern "C" const char* __asan_default_options() {
+  return "detect_leaks=0";
+}
+
 int main(int argc, const char** argv) {
   std::filesystem::path out_dir;
   std::filesystem::path include_dir;
+  std::string root_namespace = "bluetooth";
+  // Number of shards per output pybind11 cc file
+  size_t num_shards = 1;
   std::queue<std::filesystem::path> input_files;
   const std::string arg_out = "--out=";
   const std::string arg_include = "--include=";
+  const std::string arg_namespace = "--root_namespace=";
+  const std::string arg_num_shards = "--num_shards=";
 
   for (int i = 1; i < argc; i++) {
     std::string arg = argv[i];
     if (arg.find(arg_out) == 0) {
-      auto out_path = std::filesystem::path(arg.substr(arg_out.size()));
       out_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_out.size()));
     } else if (arg.find(arg_include) == 0) {
-      auto include_path = std::filesystem::path(arg.substr(arg_out.size()));
       include_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_include.size()));
+    } else if (arg.find(arg_namespace) == 0) {
+      root_namespace = arg.substr(arg_namespace.size());
+    } else if (arg.find(arg_num_shards) == 0) {
+      num_shards = std::stoul(arg.substr(arg_num_shards.size()));
     } else {
       input_files.emplace(std::filesystem::current_path() / std::filesystem::path(arg));
     }
   }
-  if (out_dir == std::filesystem::path() || include_dir == std::filesystem::path()) {
-    std::cerr << "Usage: bt-packetgen --out=OUT --include=INCLUDE input_files..." << std::endl;
+  if (out_dir == std::filesystem::path() || include_dir == std::filesystem::path() || num_shards == 0) {
+    std::cerr << "Usage: bt-packetgen --out=OUT --include=INCLUDE --root_namespace=NAMESPACE --num_shards=NUM_SHARDS "
+              << "input_files..." << std::endl;
     return 1;
   }
 
   while (!input_files.empty()) {
-    if (!parse_one_file(input_files.front(), include_dir, out_dir)) {
-      std::cerr << "Didn't parse " << input_files.front() << " correctly" << std::endl;
+    Declarations declarations;
+    if (!parse_declarations_one_file(input_files.front(), &declarations)) {
+      std::cerr << "Cannot parse " << input_files.front() << " correctly" << std::endl;
       return 2;
     }
+    if (!generate_cpp_headers_one_file(declarations, input_files.front(), include_dir, out_dir, root_namespace)) {
+      std::cerr << "Didn't generate cpp headers for " << input_files.front() << std::endl;
+      return 3;
+    }
+    if (!generate_pybind11_sources_one_file(declarations, input_files.front(), include_dir, out_dir, root_namespace,
+                                            num_shards)) {
+      std::cerr << "Didn't generate pybind11 sources for " << input_files.front() << std::endl;
+      return 4;
+    }
     input_files.pop();
   }
 
diff --git a/gd/packet/parser/packet_def.cc b/gd/packet/parser/packet_def.cc
index f4c6158..2fd4df2 100644
--- a/gd/packet/parser/packet_def.cc
+++ b/gd/packet/parser/packet_def.cc
@@ -22,8 +22,8 @@
 #include "fields/all_fields.h"
 #include "util.h"
 
-PacketDef::PacketDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr){};
-PacketDef::PacketDef(std::string name, FieldList fields, PacketDef* parent) : ParentDef(name, fields, parent){};
+PacketDef::PacketDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr) {}
+PacketDef::PacketDef(std::string name, FieldList fields, PacketDef* parent) : ParentDef(name, fields, parent) {}
 
 PacketField* PacketDef::GetNewField(const std::string&, ParseLocation) const {
   return nullptr;  // Packets can't be fields
@@ -84,15 +84,50 @@
   s << "};\n";
 }
 
+void PacketDef::GenParserDefinitionPybind11(std::ostream& s) const {
+  s << "py::class_<" << name_ << "View";
+  if (parent_ != nullptr) {
+    s << ", " << parent_->name_ << "View";
+  } else {
+    s << ", PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian>";
+  }
+  s << ">(m, \"" << name_ << "View\")";
+  if (parent_ != nullptr) {
+    s << ".def(py::init([](" << parent_->name_ << "View parent) {";
+  } else {
+    s << ".def(py::init([](PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> parent) {";
+  }
+  s << "auto view =" << name_ << "View::Create(std::move(parent));";
+  s << "if (!view.IsValid()) { throw std::invalid_argument(\"Bad packet view\"); }";
+  s << "return view; }))";
+
+  s << ".def(py::init(&" << name_ << "View::Create))";
+  std::set<std::string> protected_field_types = {
+      FixedScalarField::kFieldType,
+      FixedEnumField::kFieldType,
+      SizeField::kFieldType,
+      CountField::kFieldType,
+  };
+  const auto& public_fields = fields_.GetFieldsWithoutTypes(protected_field_types);
+  for (const auto& field : public_fields) {
+    auto getter_func_name = field->GetGetterFunctionName();
+    if (getter_func_name.empty()) {
+      continue;
+    }
+    s << ".def(\"" << getter_func_name << "\", &" << name_ << "View::" << getter_func_name << ")";
+  }
+  s << ".def(\"IsValid\", &" << name_ << "View::IsValid)";
+  s << ";\n";
+}
+
 void PacketDef::GenParserFieldGetter(std::ostream& s, const PacketField* field) const {
   // Start field offset
   auto start_field_offset = GetOffsetForField(field->GetName(), false);
   auto end_field_offset = GetOffsetForField(field->GetName(), true);
 
   if (start_field_offset.empty() && end_field_offset.empty()) {
-    std::cerr << "Field location for " << field->GetName() << " is ambiguous, "
-              << "no method exists to determine field location from begin() or end().\n";
-    abort();
+    ERROR(field) << "Field location for " << field->GetName() << " is ambiguous, "
+                 << "no method exists to determine field location from begin() or end().\n";
   }
 
   field->GenGetter(s, start_field_offset, end_field_offset);
@@ -106,7 +141,9 @@
   // Get the static offset for all of our fields.
   int bits_size = 0;
   for (const auto& field : fields_) {
-    bits_size += field->GetSize().bits();
+    if (field->GetFieldType() != PaddingField::kFieldType) {
+      bits_size += field->GetSize().bits();
+    }
   }
 
   // Write the function declaration.
@@ -281,6 +318,129 @@
 
   GenMembers(s);
   s << "};\n";
+
+  GenTestDefine(s);
+  s << "\n";
+
+  GenFuzzTestDefine(s);
+  s << "\n";
+}
+
+void PacketDef::GenBuilderDefinitionPybind11(std::ostream& s) const {
+  s << "py::class_<" << name_ << "Builder";
+  if (parent_ != nullptr) {
+    s << ", " << parent_->name_ << "Builder";
+  } else {
+    if (is_little_endian_) {
+      s << ", PacketBuilder<kLittleEndian>";
+    } else {
+      s << ", PacketBuilder<!kLittleEndian>";
+    }
+  }
+  s << ">(m, \"" << name_ << "Builder\")";
+  if (!fields_.HasBody()) {
+    GenBuilderCreatePybind11(s);
+  }
+  s << ".def(\"Serialize\", [](" << name_ << "Builder& builder){";
+  s << "std::vector<uint8_t> bytes;";
+  s << "BitInserter bi(bytes);";
+  s << "builder.Serialize(bi);";
+  s << "return bytes;})";
+  s << ";\n";
+}
+
+void PacketDef::GenTestDefine(std::ostream& s) const {
+  s << "#ifdef PACKET_TESTING\n";
+  s << "#define DEFINE_AND_INSTANTIATE_" << name_ << "ReflectionTest(...)";
+  s << "class " << name_ << "ReflectionTest : public testing::TestWithParam<std::vector<uint8_t>> { ";
+  s << "public: ";
+  s << "void CompareBytes(std::vector<uint8_t> captured_packet) {";
+  s << "auto vec = std::make_shared<std::vector<uint8_t>>(captured_packet.begin(), captured_packet.end());";
+  s << name_ << "View view = " << name_ << "View::Create(";
+  auto ancestor_ptr = parent_;
+  size_t parent_parens = 0;
+  while (ancestor_ptr != nullptr) {
+    s << ancestor_ptr->name_ << "View::Create(";
+    parent_parens++;
+    ancestor_ptr = ancestor_ptr->parent_;
+  }
+  s << "vec";
+  for (size_t i = 0; i < parent_parens; i++) {
+    s << ")";
+  }
+  s << ");";
+  s << "if (!view.IsValid()) { LOG_INFO(\"Invalid Packet Bytes (size = %zu)\", view.size());";
+  s << "for (size_t i = 0; i < view.size(); i++) { LOG_DEBUG(\"%5zd:%02X\", i, *(view.begin() + i)); }}";
+  s << "ASSERT_TRUE(view.IsValid());";
+  s << "auto packet = " << name_ << "Builder::Create(";
+  FieldList params = GetParamList().GetFieldsWithoutTypes({
+      BodyField::kFieldType,
+  });
+  for (int i = 0; i < params.size(); i++) {
+    params[i]->GenBuilderParameterFromView(s);
+    if (i != params.size() - 1) {
+      s << ", ";
+    }
+  }
+  s << ");";
+  s << "std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();";
+  s << "packet_bytes->reserve(packet->size());";
+  s << "BitInserter it(*packet_bytes);";
+  s << "packet->Serialize(it);";
+  s << "ASSERT_EQ(*packet_bytes, *vec);";
+  s << "}";
+  s << "};";
+  s << "TEST_P(" << name_ << "ReflectionTest, generatedReflectionTest) {";
+  s << "CompareBytes(GetParam());";
+  s << "}";
+  s << "INSTANTIATE_TEST_SUITE_P(" << name_ << "_reflection, ";
+  s << name_ << "ReflectionTest, testing::Values(__VA_ARGS__))";
+  s << "\n#endif";
+}
+
+void PacketDef::GenFuzzTestDefine(std::ostream& s) const {
+  s << "#ifdef PACKET_FUZZ_TESTING\n";
+  s << "#define DEFINE_AND_REGISTER_" << name_ << "ReflectionFuzzTest(REGISTRY) ";
+  s << "void Run" << name_ << "ReflectionFuzzTest(const uint8_t* data, size_t size) {";
+  s << "auto vec = std::make_shared<std::vector<uint8_t>>(data, data + size);";
+  s << name_ << "View view = " << name_ << "View::Create(";
+  auto ancestor_ptr = parent_;
+  size_t parent_parens = 0;
+  while (ancestor_ptr != nullptr) {
+    s << ancestor_ptr->name_ << "View::Create(";
+    parent_parens++;
+    ancestor_ptr = ancestor_ptr->parent_;
+  }
+  s << "vec";
+  for (size_t i = 0; i < parent_parens; i++) {
+    s << ")";
+  }
+  s << ");";
+  s << "if (!view.IsValid()) { return; }";
+  s << "auto packet = " << name_ << "Builder::Create(";
+  FieldList params = GetParamList().GetFieldsWithoutTypes({
+      BodyField::kFieldType,
+  });
+  for (int i = 0; i < params.size(); i++) {
+    params[i]->GenBuilderParameterFromView(s);
+    if (i != params.size() - 1) {
+      s << ", ";
+    }
+  }
+  s << ");";
+  s << "std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();";
+  s << "packet_bytes->reserve(packet->size());";
+  s << "BitInserter it(*packet_bytes);";
+  s << "packet->Serialize(it);";
+  s << "}";
+  s << " class " << name_ << "ReflectionFuzzTestRegistrant {";
+  s << "public: ";
+  s << "explicit " << name_
+    << "ReflectionFuzzTestRegistrant(std::vector<void(*)(const uint8_t*, size_t)>& fuzz_test_registry) {";
+  s << "fuzz_test_registry.push_back(Run" << name_ << "ReflectionFuzzTest);";
+  s << "}}; ";
+  s << name_ << "ReflectionFuzzTestRegistrant " << name_ << "_reflection_fuzz_test_registrant(REGISTRY);";
+  s << "\n#endif";
 }
 
 FieldList PacketDef::GetParametersToValidate() const {
@@ -314,7 +474,11 @@
   });
   // Add the parameters.
   for (int i = 0; i < params.size(); i++) {
-    s << params[i]->GetName();
+    if (params[i]->BuilderParameterMustBeMoved()) {
+      s << "std::move(" << params[i]->GetName() << ")";
+    } else {
+      s << params[i]->GetName();
+    }
     if (i != params.size() - 1) {
       s << ", ";
     }
@@ -328,6 +492,81 @@
   s << "}\n";
 }
 
+void PacketDef::GenBuilderCreatePybind11(std::ostream& s) const {
+  s << ".def(py::init([](";
+  auto params = GetParamList();
+  std::vector<std::string> constructor_args;
+  std::vector<std::string> keep_alive_args;
+  int i = 1;
+  for (const auto& param : params) {
+    i++;
+    std::stringstream ss;
+    auto param_type = param->GetBuilderParameterType();
+    if (param_type.empty()) {
+      continue;
+    }
+    // Use shared_ptr instead of unique_ptr for the Python interface
+    if (param->BuilderParameterMustBeMoved()) {
+      param_type = util::StringFindAndReplaceAll(param_type, "unique_ptr", "shared_ptr");
+      keep_alive_args.push_back(std::to_string(i));
+    }
+    ss << param_type << " " << param->GetName();
+    constructor_args.push_back(ss.str());
+  }
+  s << util::StringJoin(",", constructor_args) << "){";
+
+  // Deal with move only args
+  for (const auto& param : params) {
+    std::stringstream ss;
+    auto param_type = param->GetBuilderParameterType();
+    if (param_type.empty()) {
+      continue;
+    }
+    if (!param->BuilderParameterMustBeMoved()) {
+      continue;
+    }
+    auto move_only_param_name = param->GetName() + "_move_only";
+    s << param_type << " " << move_only_param_name << ";";
+    if (param->IsContainerField()) {
+      // Assume single layer container
+      s << "for (size_t i = 0; i < " << param->GetName() << ".size(); i++) {";
+      if (param->GetFieldType() == VectorField::kFieldType) {
+        s << move_only_param_name << ".emplace_back(" << param->GetName() << "[i].get());";
+      } else if (param->GetFieldType() == ArrayField::kFieldType) {
+        s << move_only_param_name << "[i].reset(" << param->GetName() << "[i].get());";
+      } else {
+        ERROR() << param << " is not supported by Pybind11";
+      }
+      s << "}";
+    } else {
+      // Release shared_ptr to unique_ptr and leave the Python copy as nullptr and to be garbage collected by Python
+      s << move_only_param_name << ".reset(" << param->GetName() << ".get());";
+    }
+  }
+  s << "return " << name_ << "Builder::Create(";
+  std::vector<std::string> builder_vars;
+  for (const auto& param : params) {
+    std::stringstream ss;
+    auto param_type = param->GetBuilderParameterType();
+    if (param_type.empty()) {
+      continue;
+    }
+    auto param_name = param->GetName();
+    if (param->BuilderParameterMustBeMoved()) {
+      ss << "std::move(" << param_name << "_move_only)";
+    } else {
+      ss << param_name;
+    }
+    builder_vars.push_back(ss.str());
+  }
+  s << util::StringJoin(",", builder_vars) << ");}";
+  if (keep_alive_args.empty()) {
+    s << "))";
+  } else {
+    s << "), py::keep_alive<1," << util::StringJoin(",", keep_alive_args) << ">())";
+  }
+}
+
 void PacketDef::GenBuilderParameterChecker(std::ostream& s) const {
   FieldList params_to_validate = GetParametersToValidate();
 
@@ -367,7 +606,11 @@
       s << ", ";
     }
   }
-  s << ") :";
+  if (params.size() > 0 || parent_constraints_.size() > 0) {
+    s << ") :";
+  } else {
+    s << ")";
+  }
 
   // Get the list of parent params to call the parent constructor with.
   FieldList parent_params;
@@ -417,7 +660,11 @@
   }
   for (int i = 0; i < saved_params.size(); i++) {
     const auto& saved_param_name = saved_params[i]->GetName();
-    s << saved_param_name << "_(" << saved_param_name << ")";
+    if (saved_params[i]->BuilderParameterMustBeMoved()) {
+      s << saved_param_name << "_(std::move(" << saved_param_name << "))";
+    } else {
+      s << saved_param_name << "_(" << saved_param_name << ")";
+    }
     if (i != saved_params.size() - 1) {
       s << ",";
     }
diff --git a/gd/packet/parser/packet_def.h b/gd/packet/parser/packet_def.h
index 4d1ddd4..e8acdc3 100644
--- a/gd/packet/parser/packet_def.h
+++ b/gd/packet/parser/packet_def.h
@@ -33,6 +33,8 @@
 
   void GenParserDefinition(std::ostream& s) const;
 
+  void GenParserDefinitionPybind11(std::ostream& s) const;
+
   void GenParserFieldGetter(std::ostream& s, const PacketField* field) const;
 
   void GenValidator(std::ostream& s) const;
@@ -41,10 +43,18 @@
 
   void GenBuilderDefinition(std::ostream& s) const;
 
+  void GenBuilderDefinitionPybind11(std::ostream& s) const;
+
+  void GenTestDefine(std::ostream& s) const;
+
+  void GenFuzzTestDefine(std::ostream& s) const;
+
   FieldList GetParametersToValidate() const;
 
   void GenBuilderCreate(std::ostream& s) const;
 
+  void GenBuilderCreatePybind11(std::ostream& s) const;
+
   void GenBuilderParameterChecker(std::ostream& s) const;
 
   void GenBuilderConstructor(std::ostream& s) const;
diff --git a/gd/packet/parser/parent_def.cc b/gd/packet/parser/parent_def.cc
index 2483d72..1557bf6 100644
--- a/gd/packet/parser/parent_def.cc
+++ b/gd/packet/parser/parent_def.cc
@@ -19,9 +19,9 @@
 #include "fields/all_fields.h"
 #include "util.h"
 
-ParentDef::ParentDef(std::string name, FieldList fields) : TypeDef(name), fields_(fields), parent_(nullptr){};
+ParentDef::ParentDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr) {}
 ParentDef::ParentDef(std::string name, FieldList fields, ParentDef* parent)
-    : TypeDef(name), fields_(fields), parent_(parent){};
+    : TypeDef(name), fields_(fields), parent_(parent) {}
 
 void ParentDef::AddParentConstraint(std::string field_name, std::variant<int64_t, std::string> value) {
   // NOTE: This could end up being very slow if there are a lot of constraints.
@@ -34,16 +34,16 @@
 
   if (constrained_field->GetFieldType() == ScalarField::kFieldType) {
     if (!std::holds_alternative<int64_t>(value)) {
-      ERROR(constrained_field) << "Attemting to constrain a scalar field to an enum value in " << parent_->name_;
+      ERROR(constrained_field) << "Attempting to constrain a scalar field to an enum value in " << parent_->name_;
     }
   } else if (constrained_field->GetFieldType() == EnumField::kFieldType) {
     if (!std::holds_alternative<std::string>(value)) {
-      ERROR(constrained_field) << "Attemting to constrain an enum field to a scalar value in " << parent_->name_;
+      ERROR(constrained_field) << "Attempting to constrain an enum field to a scalar value in " << parent_->name_;
     }
     const auto& enum_def = static_cast<EnumField*>(constrained_field)->GetEnumDef();
     if (!enum_def.HasEntry(std::get<std::string>(value))) {
       ERROR(constrained_field) << "No matching enumeration \"" << std::get<std::string>(value)
-                               << "for constraint on enum in parent " << parent_->name_ << ".";
+                               << "\" for constraint on enum in parent " << parent_->name_ << ".";
     }
 
     // For enums, we have to qualify the value using the enum type name.
@@ -98,8 +98,7 @@
 
     // If we've reached this point then the field wasn't a variable length field.
     // Check to see if the field is a variable length field
-    std::cerr << "Can not use size/count in reference to a fixed size field.\n";
-    abort();
+    ERROR(field, size_field) << "Can not use size/count in reference to a fixed size field.\n";
   }
 }
 
@@ -160,12 +159,7 @@
 Size ParentDef::GetOffsetForField(std::string field_name, bool from_end) const {
   // Check first if the field exists.
   if (fields_.GetField(field_name) == nullptr) {
-    if (field_name != "payload" && field_name != "body") {
-      ERROR() << "Can't find a field offset for nonexistent field named: " << field_name;
-    } else {
-      // TODO: Why is this a good idea?
-      return Size();
-    }
+    ERROR() << "Can't find a field offset for nonexistent field named: " << field_name << " in " << name_;
   }
 
   // We have to use a generic lambda to conditionally change iteration direction
@@ -176,12 +170,13 @@
       // We've reached the field, end the loop.
       if ((*it)->GetName() == field_name) break;
       const auto& field = *it;
-      // If there was a field that wasn't the payload with an unknown size,
-      // return an empty Size.
+      // If there is a field with an unknown size before the field, return an empty Size.
       if (field->GetSize().empty()) {
         return Size();
       }
-      size += field->GetSize();
+      if (field->GetFieldType() != PaddingField::kFieldType || !from_end) {
+        size += field->GetSize();
+      }
     }
     return size;
   };
@@ -192,20 +187,22 @@
     size = size_lambda(fields_.rbegin(), fields_.rend());
   else
     size = size_lambda(fields_.begin(), fields_.end());
-  if (size.empty()) return Size();
+  if (size.empty()) return size;
 
   // We need the offset until a payload or body field.
   if (parent_ != nullptr) {
-    auto parent_payload_offset = parent_->GetOffsetForField("payload", from_end);
-    if (!parent_payload_offset.empty()) {
+    if (parent_->fields_.HasPayload()) {
+      auto parent_payload_offset = parent_->GetOffsetForField("payload", from_end);
+      if (parent_payload_offset.empty()) {
+        ERROR() << "Empty offset for payload in " << parent_->name_ << " finding the offset for field: " << field_name;
+      }
       size += parent_payload_offset;
     } else {
-      parent_payload_offset = parent_->GetOffsetForField("body", from_end);
-      if (!parent_payload_offset.empty()) {
-        size += parent_payload_offset;
-      } else {
-        return Size();
+      auto parent_body_offset = parent_->GetOffsetForField("body", from_end);
+      if (parent_body_offset.empty()) {
+        ERROR() << "Empty offset for body in " << parent_->name_ << " finding the offset for field: " << field_name;
       }
+      size += parent_body_offset;
     }
   }
 
@@ -216,8 +213,14 @@
   FieldList params;
 
   std::set<std::string> param_types = {
-      ScalarField::kFieldType, EnumField::kFieldType,   ArrayField::kFieldType,   VectorField::kFieldType,
-      CustomField::kFieldType, StructField::kFieldType, PayloadField::kFieldType,
+      ScalarField::kFieldType,
+      EnumField::kFieldType,
+      ArrayField::kFieldType,
+      VectorField::kFieldType,
+      CustomField::kFieldType,
+      StructField::kFieldType,
+      VariableLengthStructField::kFieldType,
+      PayloadField::kFieldType,
   };
 
   if (parent_ != nullptr) {
@@ -289,8 +292,22 @@
     s << ";}\n\n";
   }
 
+  Size padded_size;
+  for (const auto& field : header_fields) {
+    if (field->GetFieldType() == PaddingField::kFieldType) {
+      if (!padded_size.empty()) {
+        ERROR() << "Only one padding field is allowed.  Second field: " << field->GetName();
+      }
+      padded_size = field->GetSize();
+    }
+  }
+
   s << "public:";
   s << "virtual size_t size() const override {";
+  if (!padded_size.empty()) {
+    s << "return " << padded_size.bytes() << ";}";
+    s << "size_t unpadded_size() const {";
+  }
   s << "return (BitsOfHeader() / 8)";
   if (fields_.HasPayload()) {
     s << "+ payload_->size()";
@@ -340,17 +357,22 @@
         }
         const auto& vector_name = field_name + "_";
         const VectorField* vector = (VectorField*)sized_field;
-        s << "size_t " << vector_name + "bytes =  0;";
-        if (vector->element_size_ == -1) {
+        s << "size_t " << vector_name + "bytes = 0;";
+        if (vector->element_size_.empty() || vector->element_size_.has_dynamic()) {
           s << "for (auto elem : " << vector_name << ") {";
           s << vector_name + "bytes += elem.size(); }";
         } else {
           s << vector_name + "bytes = ";
-          s << vector_name << ".size() * (" << vector->element_size_ << " / 8);";
+          s << vector_name << ".size() * ((" << vector->element_size_ << ") / 8);";
+        }
+        std::string modifier = vector->GetSizeModifier();
+        if (modifier != "") {
+          s << "static_assert((" << modifier << ")%8 == 0, \"Modifiers must be byte-aligned\");";
+          s << vector_name << "bytes = ";
+          s << vector_name << "bytes + (" << modifier << ") / 8;";
         }
         s << "ASSERT(" << vector_name + "bytes < (1 << " << field->GetSize().bits() << "));";
-        s << "insert(" << vector_name << "bytes";
-        s << vector->GetSizeModifier() << ", i, ";
+        s << "insert(" << vector_name << "bytes, i, ";
         s << field->GetSize().bits() << ");";
       }
     } else if (field->GetFieldType() == ChecksumStartField::kFieldType) {
@@ -365,6 +387,11 @@
       s << "i.RegisterObserver(packet::ByteObserver(";
       s << "[shared_checksum_ptr](uint8_t byte){ shared_checksum_ptr->AddByte(byte);},";
       s << "[shared_checksum_ptr](){ return static_cast<uint64_t>(shared_checksum_ptr->GetChecksum());}));";
+    } else if (field->GetFieldType() == PaddingField::kFieldType) {
+      s << "ASSERT(unpadded_size() <= " << field->GetSize().bytes() << ");";
+      s << "size_t padding_bytes = ";
+      s << field->GetSize().bytes() << " - unpadded_size();";
+      s << "for (size_t padding = 0; padding < padding_bytes; padding++) {i.insert_byte(0);}";
     } else if (field->GetFieldType() == CountField::kFieldType) {
       const auto& vector_name = ((SizeField*)field)->GetSizedFieldName() + "_";
       s << "insert(" << vector_name << ".size(), i, " << field->GetSize().bits() << ");";
@@ -402,3 +429,33 @@
 
   s << "}\n";
 }
+
+void ParentDef::GenInstanceOf(std::ostream& s) const {
+  if (parent_ != nullptr && parent_constraints_.size() > 0) {
+    s << "static bool IsInstance(const " << parent_->name_ << "& parent) {";
+    // Get the list of parent params.
+    FieldList parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+        PayloadField::kFieldType,
+        BodyField::kFieldType,
+    });
+
+    // Check if constrained parent fields are set to their correct values.
+    for (int i = 0; i < parent_params.size(); i++) {
+      const auto& field = parent_params[i];
+      const auto& constraint = parent_constraints_.find(field->GetName());
+      if (constraint != parent_constraints_.end()) {
+        s << "if (parent." << field->GetName() << "_ != ";
+        if (field->GetFieldType() == ScalarField::kFieldType) {
+          s << std::get<int64_t>(constraint->second) << ")";
+          s << "{ return false;}";
+        } else if (field->GetFieldType() == EnumField::kFieldType) {
+          s << std::get<std::string>(constraint->second) << ")";
+          s << "{ return false;}";
+        } else {
+          ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+        }
+      }
+    }
+    s << "return true;}";
+  }
+}
diff --git a/gd/packet/parser/parent_def.h b/gd/packet/parser/parent_def.h
index 7b677d8..a293a26 100644
--- a/gd/packet/parser/parent_def.h
+++ b/gd/packet/parser/parent_def.h
@@ -59,6 +59,8 @@
 
   void GenSerialize(std::ostream& s) const;
 
+  void GenInstanceOf(std::ostream& s) const;
+
   FieldList fields_;
 
   ParentDef* parent_{nullptr};
diff --git a/gd/packet/parser/struct_def.cc b/gd/packet/parser/struct_def.cc
index 1496f51..bdeb780 100644
--- a/gd/packet/parser/struct_def.cc
+++ b/gd/packet/parser/struct_def.cc
@@ -19,18 +19,15 @@
 #include "fields/all_fields.h"
 #include "util.h"
 
-StructDef::StructDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr){};
-StructDef::StructDef(std::string name, FieldList fields, StructDef* parent) : ParentDef(name, fields, parent){};
+StructDef::StructDef(std::string name, FieldList fields) : StructDef(name, fields, nullptr) {}
+StructDef::StructDef(std::string name, FieldList fields, StructDef* parent)
+    : ParentDef(name, fields, parent), total_size_(GetSize(true)) {}
 
 PacketField* StructDef::GetNewField(const std::string& name, ParseLocation loc) const {
-  Size total_size = GetSize(false);
   if (fields_.HasBody()) {
-    ERROR(new StructField(name, name_, -1, loc)) << "Variable size structs are not supported";
-    fprintf(stderr, "total_size of %s(%s) = %s\n", name_.c_str(), name.c_str(), total_size.ToString().c_str());
-    abort();
-    return new StructField(name, name_, -1, loc);
+    return new VariableLengthStructField(name, name_, loc);
   } else {
-    return new StructField(name, name_, total_size.bits(), loc);
+    return new StructField(name, name_, total_size_, loc);
   }
 }
 
@@ -38,39 +35,108 @@
   return TypeDef::Type::STRUCT;
 }
 
+void StructDef::GenSpecialize(std::ostream& s) const {
+  if (parent_ == nullptr) {
+    return;
+  }
+  s << "static " << name_ << "* Specialize(" << parent_->name_ << "* parent) {";
+  s << "ASSERT(" << name_ << "::IsInstance(*parent));";
+  s << "return static_cast<" << name_ << "*>(parent);";
+  s << "}";
+}
+
 void StructDef::GenParse(std::ostream& s) const {
-  if (is_little_endian_) {
-    s << "static Iterator<kLittleEndian> Parse(std::vector<" << name_ << ">& vec, Iterator<kLittleEndian> struct_it) {";
+  std::string iterator = (is_little_endian_ ? "Iterator<kLittleEndian>" : "Iterator<!kLittleEndian>");
+
+  if (fields_.HasBody()) {
+    s << "static std::optional<" << iterator << ">";
   } else {
-    s << "static Iterator<!kLittleEndian> Parse(std::vector<" << name_
-      << ">& vec, Iterator<!kLittleEndian> struct_it) {";
+    s << "static " << iterator;
   }
-  s << "auto begin_it = struct_it;";
-  s << "size_t end_index = struct_it.NumBytesRemaining();";
-  s << "if (end_index < " << GetSize().bytes() << ") { return struct_it + struct_it.NumBytesRemaining();}";
-  s << name_ << " one;";
+
+  s << " Parse(" << name_ << "* to_fill, " << iterator << " struct_begin_it ";
+
   if (parent_ != nullptr) {
-    s << "begin_it += one." << parent_->name_ << "::BitsOfHeader() / 8;";
+    s << ", bool fill_parent = true) {";
+  } else {
+    s << ") {";
   }
-  Size field_offset = Size(0);
+  s << "auto to_bound = struct_begin_it;";
+
+  if (parent_ != nullptr) {
+    s << "if (fill_parent) {";
+    std::string parent_param = (parent_->parent_ == nullptr ? "" : ", true");
+    if (parent_->fields_.HasBody()) {
+      s << "auto parent_optional_it = " << parent_->name_ << "::Parse(to_fill, to_bound" << parent_param << ");";
+      if (fields_.HasBody()) {
+        s << "if (!parent_optional_it) { return {}; }";
+      } else {
+        s << "ASSERT(parent_optional_it);";
+      }
+    } else {
+      s << parent_->name_ << "::Parse(to_fill, to_bound" << parent_param << ");";
+    }
+    s << "}";
+  }
+
+  if (!fields_.HasBody()) {
+    s << "size_t end_index = struct_begin_it.NumBytesRemaining();";
+    if (parent_ != nullptr) {
+      s << "if (end_index < " << GetSize().bytes() << " - to_fill->" << parent_->name_ << "::size())";
+    } else {
+      s << "if (end_index < " << GetSize().bytes() << ")";
+    }
+    s << "{ return struct_begin_it.Subrange(0,0);}";
+  }
+
   for (const auto& field : fields_) {
-    Size next_field_offset = field->GetSize() + field_offset.bits();
     if (field->GetFieldType() != ReservedField::kFieldType && field->GetFieldType() != BodyField::kFieldType &&
         field->GetFieldType() != FixedScalarField::kFieldType && field->GetFieldType() != SizeField::kFieldType &&
         field->GetFieldType() != ChecksumStartField::kFieldType && field->GetFieldType() != ChecksumField::kFieldType &&
         field->GetFieldType() != CountField::kFieldType) {
       s << "{";
-      field->GenExtractor(s, field_offset, next_field_offset);
-      s << "one." << field->GetName() << "_ = value;";
+      s << "if (to_bound.NumBytesRemaining() < " << field->GetSize().bytes() << ")";
+      if (!fields_.HasBody()) {
+        s << "{ return to_bound.Subrange(to_bound.NumBytesRemaining(),0);}";
+      } else {
+        s << "{ return {};}";
+      }
+      int num_leading_bits =
+          field->GenBounds(s, GetStructOffsetForField(field->GetName()), Size(), field->GetStructSize());
+      s << "auto " << field->GetName() << "_ptr = &to_fill->" << field->GetName() << "_;";
+      field->GenExtractor(s, num_leading_bits, true);
       s << "}";
     }
-    field_offset = next_field_offset;
+    if (field->GetFieldType() == CountField::kFieldType || field->GetFieldType() == SizeField::kFieldType) {
+      s << field->GetDataType() << " " << field->GetName() << "_extracted;";
+      s << "{";
+      s << "if (to_bound.NumBytesRemaining() < " << field->GetSize().bytes() << ")";
+      if (!fields_.HasBody()) {
+        s << "{ return to_bound.Subrange(to_bound.NumBytesRemaining(),0);}";
+      } else {
+        s << "{ return {};}";
+      }
+      int num_leading_bits =
+          field->GenBounds(s, GetStructOffsetForField(field->GetName()), Size(), field->GetStructSize());
+      s << "auto " << field->GetName() << "_ptr = &" << field->GetName() << "_extracted;";
+      field->GenExtractor(s, num_leading_bits, true);
+      s << "}";
+    }
   }
-  s << "vec.push_back(one);";
-  s << "return struct_it + " << field_offset.bytes() << ";";
+  s << "return struct_begin_it + to_fill->" << name_ << "::size();";
   s << "}";
 }
 
+void StructDef::GenParseFunctionPrototype(std::ostream& s) const {
+  s << "std::unique_ptr<" << name_ << "> Parse" << name_ << "(";
+  if (is_little_endian_) {
+    s << "Iterator<kLittleEndian>";
+  } else {
+    s << "Iterator<!kLittleEndian>";
+  }
+  s << "it);";
+}
+
 void StructDef::GenDefinition(std::ostream& s) const {
   s << "class " << name_;
   if (parent_ != nullptr) {
@@ -87,11 +153,6 @@
 
   GenConstructor(s);
 
-  std::set<std::string> fixed_types = {
-      FixedScalarField::kFieldType,
-      FixedEnumField::kFieldType,
-  };
-
   s << " public:\n";
   s << "  virtual ~" << name_ << "() override = default;\n";
 
@@ -104,12 +165,42 @@
   GenSize(s);
   s << "\n";
 
+  GenInstanceOf(s);
+  s << "\n";
+
+  GenSpecialize(s);
+  s << "\n";
+
   GenMembers(s);
   s << "};\n";
+
+  if (fields_.HasBody()) {
+    GenParseFunctionPrototype(s);
+  }
+  s << "\n";
+}
+
+void StructDef::GenDefinitionPybind11(std::ostream& s) const {
+  s << "py::class_<" << name_;
+  if (parent_ != nullptr) {
+    s << ", " << parent_->name_;
+  } else {
+    if (is_little_endian_) {
+      s << ", PacketStruct<kLittleEndian>";
+    } else {
+      s << ", PacketStruct<!kLittleEndian>";
+    }
+  }
+  s << ">(m, \"" << name_ << "\")";
+  s << ".def(py::init<>())";
+  s << ".def(\"Serialize\", &" << GetTypeName() << "::Serialize)";
+  s << ".def(\"Parse\", &" << name_ << "::Parse)";
+  s << ";\n";
 }
 
 void StructDef::GenConstructor(std::ostream& s) const {
   if (parent_ != nullptr) {
+    s << name_ << "(const " << parent_->name_ << "& parent) : " << parent_->name_ << "(parent) {}";
     s << name_ << "() : " << parent_->name_ << "() {";
   } else {
     s << name_ << "() {";
@@ -142,3 +233,28 @@
 
   s << "}\n";
 }
+
+Size StructDef::GetStructOffsetForField(std::string field_name) const {
+  auto size = Size(0);
+  for (auto it = fields_.begin(); it != fields_.end(); it++) {
+    // We've reached the field, end the loop.
+    if ((*it)->GetName() == field_name) break;
+    const auto& field = *it;
+    // When we need to parse this field, all previous fields should already be parsed.
+    if (field->GetStructSize().empty()) {
+      ERROR() << "Empty size for field " << (*it)->GetName() << " finding the offset for field: " << field_name;
+    }
+    size += field->GetStructSize();
+  }
+
+  // We need the offset until a body field.
+  if (parent_ != nullptr) {
+    auto parent_body_offset = static_cast<StructDef*>(parent_)->GetStructOffsetForField("body");
+    if (parent_body_offset.empty()) {
+      ERROR() << "Empty offset for body in " << parent_->name_ << " finding the offset for field: " << field_name;
+    }
+    size += parent_body_offset;
+  }
+
+  return size;
+}
diff --git a/gd/packet/parser/struct_def.h b/gd/packet/parser/struct_def.h
index 1b3d969..74c1b04 100644
--- a/gd/packet/parser/struct_def.h
+++ b/gd/packet/parser/struct_def.h
@@ -34,9 +34,20 @@
 
   TypeDef::Type GetDefinitionType() const;
 
+  void GenSpecialize(std::ostream& s) const;
+
   void GenParse(std::ostream& s) const;
 
+  void GenParseFunctionPrototype(std::ostream& s) const;
+
   void GenDefinition(std::ostream& s) const;
 
+  void GenDefinitionPybind11(std::ostream& s) const;
+
   void GenConstructor(std::ostream& s) const;
+
+  Size GetStructOffsetForField(std::string field_name) const;
+
+ private:
+  Size total_size_;
 };
diff --git a/gd/packet/parser/struct_parser_generator.cc b/gd/packet/parser/struct_parser_generator.cc
new file mode 100644
index 0000000..352219e
--- /dev/null
+++ b/gd/packet/parser/struct_parser_generator.cc
@@ -0,0 +1,98 @@
+/*
+ * 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 "struct_parser_generator.h"
+
+StructParserGenerator::StructParserGenerator(const Declarations& decls) {
+  is_little_endian = decls.is_little_endian;
+  for (const auto& s : decls.type_defs_queue_) {
+    if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+      const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+      variable_struct_fields_.emplace_back(struct_def);
+    }
+  }
+  for (const auto& node : variable_struct_fields_) {
+    if (node.struct_def_->parent_ != nullptr) {
+      for (auto& parent : variable_struct_fields_) {
+        if (node.struct_def_->parent_->name_ == parent.struct_def_->name_) {
+          parent.children_.push_back(&node);
+        }
+      }
+    }
+  }
+}
+
+void StructParserGenerator::explore_children(const TreeNode& node, std::ostream& s) const {
+  auto field = node.packet_field_;
+  if (!node.children_.empty()) {
+    s << "bool " << field->GetName() << "_child_found = false; /* Greedy match */";
+  }
+  for (const auto& child : node.children_) {
+    s << "if (!" << field->GetName() << "_child_found && ";
+    s << child->struct_def_->name_ << "::IsInstance(*" << field->GetName() << "_value.get())) {";
+    s << field->GetName() << "_child_found = true;";
+    s << "std::unique_ptr<" << child->struct_def_->name_ << "> " << child->packet_field_->GetName() << "_value;";
+    s << child->packet_field_->GetName() << "_value.reset(new ";
+    s << child->struct_def_->name_ << "(*" << field->GetName() << "_value));";
+    if (child->struct_def_->fields_.HasBody()) {
+      s << "auto optional_it = ";
+      s << child->struct_def_->name_ << "::Parse( " << child->packet_field_->GetName() << "_value.get(), ";
+      s << "to_bound, false);";
+      s << "if (optional_it) {";
+      s << "} else { return " << field->GetName() << "_value;}";
+    } else {
+      s << child->struct_def_->name_ << "::Parse( " << child->packet_field_->GetName() << "_value.get(), ";
+      s << "to_bound, false);";
+    }
+    explore_children(*child, s);
+    s << field->GetName() << "_value = std::move(" << child->packet_field_->GetName() << "_value);";
+
+    s << " }";
+  }
+}
+
+void StructParserGenerator::Generate(std::ostream& s) const {
+  for (const auto& node : variable_struct_fields_) {
+    if (node.children_.empty()) {
+      continue;
+    }
+    auto field = node.packet_field_;
+    s << "inline std::unique_ptr<" << node.struct_def_->name_ << "> Parse" << node.struct_def_->name_;
+    if (is_little_endian) {
+      s << "(Iterator<kLittleEndian> to_bound) {";
+    } else {
+      s << "(Iterator<!kLittleEndian> to_bound) {";
+    }
+    s << field->GetDataType() << " " << field->GetName() << "_value = ";
+    s << "std::make_unique<" << node.struct_def_->name_ << ">();";
+
+    s << "auto " << field->GetName() << "_it = to_bound;";
+    s << "auto optional_it = ";
+    s << node.struct_def_->name_ << "::Parse( " << field->GetName() << "_value.get(), ";
+    s << field->GetName() << "_it";
+    if (node.struct_def_->parent_ != nullptr) {
+      s << ", true);";
+    } else {
+      s << ");";
+    }
+    s << "if (optional_it) {";
+    s << field->GetName() << "_it = *optional_it;";
+    s << "} else { return nullptr; }";
+
+    explore_children(node, s);
+    s << "return " << field->GetName() << "_value; }";
+  }
+}
diff --git a/gd/packet/parser/struct_parser_generator.h b/gd/packet/parser/struct_parser_generator.h
new file mode 100644
index 0000000..0315460
--- /dev/null
+++ b/gd/packet/parser/struct_parser_generator.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <iostream>
+
+#include "declarations.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class StructParserGenerator {
+ public:
+  explicit StructParserGenerator(const Declarations& declarations);
+
+  void Generate(std::ostream& s) const;
+
+ private:
+  class TreeNode {
+   public:
+    explicit TreeNode(const StructDef* s)
+        : struct_def_(s), packet_field_(s->GetNewField(s->name_ + "_parse", ParseLocation())) {}
+    const StructDef* struct_def_;
+    const PacketField* packet_field_;
+    std::list<const TreeNode*> children_;
+  };
+  std::list<TreeNode> variable_struct_fields_;
+  bool is_little_endian;
+
+  void explore_children(const TreeNode& node, std::ostream& s) const;
+};
diff --git a/gd/packet/parser/test/Android.bp b/gd/packet/parser/test/Android.bp
index 3b3eccd..65b2f3e 100644
--- a/gd/packet/parser/test/Android.bp
+++ b/gd/packet/parser/test/Android.bp
@@ -6,9 +6,11 @@
     cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) $(in)",
     srcs: [
         "test_packets.pdl",
+        "big_endian_test_packets.pdl",
     ],
     out: [
         "packet/parser/test/test_packets.h",
+        "packet/parser/test/big_endian_test_packets.h",
     ],
 }
 
diff --git a/gd/packet/parser/test/big_endian_test_packets.pdl b/gd/packet/parser/test/big_endian_test_packets.pdl
new file mode 100644
index 0000000..5647ea6
--- /dev/null
+++ b/gd/packet/parser/test/big_endian_test_packets.pdl
@@ -0,0 +1,266 @@
+big_endian_packets
+
+custom_field SixBytes : 48 "packet/parser/test/"
+custom_field Variable "packet/parser/test/"
+
+packet ParentBe {
+  _fixed_ = 0x12 : 8,
+  _size_(_payload_) : 8,
+  _payload_,
+  footer : 8,
+}
+
+packet ChildBe  : ParentBe {
+  field_name : 16,
+}
+
+enum FourBitsBe : 4 {
+  ONE = 1,
+  TWO = 2,
+  THREE = 3,
+  FIVE = 5,
+  TEN = 10,
+  LAZY_ME = 15,
+}
+
+packet ParentTwoBe {
+  _reserved_ : 4,
+  four_bits : FourBitsBe,
+  _payload_,
+}
+
+packet ChildTwoThreeBe  : ParentTwoBe (four_bits = THREE) {
+  more_bits : FourBitsBe,
+  _reserved_ : 4,
+  sixteen_bits : 16
+}
+
+packet ChildTwoTwoBe  : ParentTwoBe (four_bits = TWO) {
+  more_bits : FourBitsBe,
+  _reserved_ : 4,
+}
+
+packet ChildTwoTwoThreeBe  :ChildTwoTwoBe (more_bits = THREE) {
+}
+
+enum TwoBitsBe : 2 {
+  ZERO = 0,
+  ONE = 1,
+  TWO = 2,
+  THREE = 3,
+}
+
+packet MiddleFourBitsBe {
+  low_two : TwoBitsBe,
+  next_four : FourBitsBe,
+  straddle : FourBitsBe,
+  four_more : FourBitsBe,
+  high_two : TwoBitsBe,
+}
+
+packet ParentWithSixBytesBe {
+  two_bytes : 16,
+  six_bytes : SixBytes,
+  _payload_,
+}
+
+packet ChildWithSixBytesBe  : ParentWithSixBytesBe (two_bytes = 0x1234) {
+  child_six_bytes : SixBytes,
+}
+
+checksum SimpleSum : 16 "packet/parser/test/"
+
+packet ParentWithSumBe {
+  two_bytes : 16,
+  _checksum_start_(example_checksum),
+  sum_bytes : 16,
+  _payload_,
+  example_checksum : SimpleSum,
+}
+
+packet ChildWithSumBe  : ParentWithSumBe {
+  more_bytes : 32,
+  another_byte : 8,
+}
+
+packet ChildWithNestedSumBe  : ParentWithSumBe {
+  _checksum_start_(nested_checksum),
+  more_bytes : 32,
+  nested_checksum : SimpleSum,
+}
+
+packet ParentSizeModifierBe {
+  _size_(_payload_) : 8,
+  _payload_ : [+2*8], // Include two_bytes in the size
+  two_bytes : 16,
+}
+
+packet ChildSizeModifierBe  : ParentSizeModifierBe (two_bytes = 0x1211) {
+  more_bytes : 32,
+}
+
+enum ForArraysBe : 16 {
+  ONE = 0x0001,
+  TWO = 0x0002,
+  ONE_TWO = 0x0201,
+  TWO_THREE = 0x0302,
+  FFFF = 0xffff,
+}
+
+packet FixedArrayEnumBe {
+  enum_array : ForArraysBe[5],
+}
+
+packet SizedArrayEnumBe {
+  _size_(enum_array) : 16,
+  enum_array : ForArraysBe[],
+}
+
+packet CountArrayEnumBe {
+  _count_(enum_array) : 8,
+  enum_array : ForArraysBe[],
+}
+
+packet SizedArrayCustomBe {
+  _size_(six_bytes_array) : 8,
+  an_extra_byte : 8,
+  six_bytes_array : SixBytes[+1*8],
+}
+
+packet FixedArrayCustomBe {
+  six_bytes_array : SixBytes[5],
+}
+
+packet CountArrayCustomBe {
+  _count_(six_bytes_array) : 8,
+  six_bytes_array : SixBytes[],
+}
+
+packet PacketWithFixedArraysOfBytesBe {
+  fixed_256bit_in_bytes : 8[32],
+  fixed_256bit_in_words : 32[8],
+}
+
+packet OneVariableBe {
+  one : Variable,
+}
+
+packet SizedArrayVariableBe {
+  _size_(variable_array) : 8,
+  variable_array : Variable[],
+}
+
+packet FixedArrayVariableBe {
+  variable_array : Variable[5],
+}
+
+packet CountArrayVariableBe {
+  _count_(variable_array) : 8,
+  variable_array : Variable[],
+}
+
+struct TwoRelatedNumbersBe {
+  id : 8,
+  count : 16,
+}
+
+packet OneStructBe {
+  one : TwoRelatedNumbersBe,
+}
+
+packet TwoStructsBe {
+  one : TwoRelatedNumbersBe,
+  two : TwoRelatedNumbersBe,
+}
+
+packet ArrayOfStructBe {
+  _count_(array) : 8,
+  array : TwoRelatedNumbersBe[],
+}
+
+struct StructWithFixedTypesBe {
+  four_bits : FourBitsBe,
+  _reserved_ : 4,
+  _checksum_start_(example_checksum),
+  _fixed_ = 0xf3 : 8,
+  id : 8,
+  array : 8[3],
+  example_checksum : SimpleSum,
+  six_bytes : SixBytes,
+}
+
+packet OneFixedTypesStructBe {
+  one : StructWithFixedTypesBe,
+}
+
+packet ArrayOfStructAndAnotherBe {
+  _count_(array) : 8,
+  array : TwoRelatedNumbersBe[],
+  another : TwoRelatedNumbersBe,
+}
+
+group BitFieldGroupBe {
+  seven_bits : 7,
+  straddle : 4,
+  five_bits : 5,
+}
+
+packet BitFieldGroupPacketBe {
+  BitFieldGroupBe,
+}
+
+packet BitFieldGroupAfterPayloadPacketBe {
+  _payload_,
+  BitFieldGroupBe,
+}
+
+packet BitFieldGroupAfterUnsizedArrayPacketBe  : BitFieldGroupAfterPayloadPacketBe {
+  array : 8[],
+}
+
+struct BitFieldBe {
+  seven_bits : 7,
+  straddle : 4,
+  five_bits : 5,
+}
+
+packet BitFieldPacketBe {
+  bit_field : BitFieldBe,
+}
+
+packet BitFieldAfterPayloadPacketBe {
+  _payload_,
+  bit_field : BitFieldBe,
+}
+
+packet BitFieldAfterUnsizedArrayPacketBe  : BitFieldAfterPayloadPacketBe {
+  array : 8[],
+}
+
+packet BitFieldArrayPacketBe {
+  _size_(array): 8,
+  array : BitFieldBe[],
+}
+
+struct VersionlessStructBe {
+  one_number : 8,
+}
+
+packet OneVersionlessStructPacketBe {
+  versionless : VersionlessStructBe,
+  _payload_,
+}
+
+packet OneVersionedStructPacketBe  : OneVersionlessStructPacketBe {
+  version : 8,
+  _payload_,
+}
+
+packet OneVersionOneStructPacketBe  : OneVersionedStructPacketBe (version = 0x01) {
+  just_one_number : 8,
+}
+
+packet OneVersionTwoStructPacketBe  : OneVersionedStructPacketBe (version = 0x02) {
+  one_number : 8,
+  another_number : 8,
+}
diff --git a/gd/packet/parser/test/generated_packet_test.cc b/gd/packet/parser/test/generated_packet_test.cc
index b510522..06f60b5 100644
--- a/gd/packet/parser/test/generated_packet_test.cc
+++ b/gd/packet/parser/test/generated_packet_test.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define PACKET_TESTING
+#include "packet/parser/test/big_endian_test_packets.h"
 #include "packet/parser/test/test_packets.h"
 
 #include <gtest/gtest.h>
@@ -448,6 +450,10 @@
   auto packet = FixedArrayEnumBuilder::Create(fixed_array);
   ASSERT_EQ(fixed_array_enum.size(), packet->size());
 
+  // Verify that the packet is independent from the array.
+  std::array<ForArrays, 5> copy_array(fixed_array);
+  fixed_array[1] = ForArrays::ONE;
+
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter it(*packet_bytes);
   packet->Serialize(it);
@@ -461,9 +467,9 @@
   auto view = FixedArrayEnumView::Create(packet_bytes_view);
   ASSERT_TRUE(view.IsValid());
   auto array = view.GetEnumArray();
-  ASSERT_EQ(fixed_array.size(), array.size());
-  for (size_t i = 0; i < fixed_array.size(); i++) {
-    ASSERT_EQ(array[i], fixed_array[i]);
+  ASSERT_EQ(copy_array.size(), array.size());
+  for (size_t i = 0; i < copy_array.size(); i++) {
+    ASSERT_EQ(array[i], copy_array[i]);
   }
 }
 
@@ -490,6 +496,10 @@
   auto packet = SizedArrayEnumBuilder::Create(sized_array);
   ASSERT_EQ(sized_array_enum.size(), packet->size());
 
+  // Copy the original vector and modify it to make sure the packet is independent.
+  std::vector<ForArrays> copy_array(sized_array);
+  sized_array[1] = ForArrays::ONE;
+
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter it(*packet_bytes);
   packet->Serialize(it);
@@ -503,9 +513,9 @@
   auto view = SizedArrayEnumView::Create(packet_bytes_view);
   ASSERT_TRUE(view.IsValid());
   auto array = view.GetEnumArray();
-  ASSERT_EQ(sized_array.size(), array.size());
-  for (size_t i = 0; i < sized_array.size(); i++) {
-    ASSERT_EQ(array[i], sized_array[i]);
+  ASSERT_EQ(copy_array.size(), array.size());
+  for (size_t i = 0; i < copy_array.size(); i++) {
+    ASSERT_EQ(array[i], copy_array[i]);
   }
 }
 
@@ -588,10 +598,9 @@
 };
 
 TEST(GeneratedPacketTest, testOneVariableField) {
-  std::vector<Variable> sized_array;
-  sized_array.emplace_back("one");
+  Variable variable_one{"one"};
 
-  auto packet = OneVariableBuilder::Create(sized_array[0]);
+  auto packet = OneVariableBuilder::Create(variable_one);
   ASSERT_EQ(one_variable.size(), packet->size());
 
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
@@ -606,11 +615,21 @@
   PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
   auto view = OneVariableView::Create(packet_bytes_view);
   ASSERT_TRUE(view.IsValid());
-  auto array = view.GetOne();
-  ASSERT_EQ(sized_array.size(), array.size());
-  for (size_t i = 0; i < sized_array.size(); i++) {
-    ASSERT_EQ(array[i].data, sized_array[i].data);
-  }
+  auto one = view.GetOne();
+  ASSERT_EQ(one->data, variable_one.data);
+}
+
+vector<uint8_t> fou_variable{
+    0x04, 'f', 'o', 'u',  // too short
+};
+
+TEST(GeneratedPacketTest, testOneVariableFieldTooShort) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>(fou_variable);
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one, nullptr);
 }
 
 vector<uint8_t> sized_array_variable{
@@ -648,6 +667,55 @@
   }
 }
 
+vector<uint8_t> sized_array_variable_too_short{
+    0x0e,                           // _size_
+    0x03, 'o', 'n', 'e',            // "one"
+    0x03, 't', 'w', 'o',            // "two"
+    0x06, 't', 'h', 'r', 'e', 'e',  // "three" needs another letter to be length 6
+};
+
+TEST(GeneratedPacketTest, testSizedArrayVariableLengthLastBad) {
+  std::vector<Variable> sized_array;
+  sized_array.emplace_back("one");
+  sized_array.emplace_back("two");
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(sized_array_variable_too_short);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = SizedArrayVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetVariableArray();
+  ASSERT_EQ(sized_array.size(), array.size());
+  for (size_t i = 0; i < sized_array.size(); i++) {
+    ASSERT_EQ(array[i].data, sized_array[i].data);
+  }
+}
+
+vector<uint8_t> sized_array_variable_first_too_short{
+    0x0e,                           // _size_
+    0x02, 'o', 'n', 'e',            // "on"
+    0x03, 't', 'w', 'o',            // "two"
+    0x05, 't', 'h', 'r', 'e', 'e',  // "three"
+};
+
+TEST(GeneratedPacketTest, testSizedArrayVariableLengthFirstBad) {
+  std::vector<Variable> sized_array;
+  sized_array.emplace_back("on");
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(sized_array_variable_first_too_short);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = SizedArrayVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetVariableArray();
+  ASSERT_EQ(sized_array.size(), array.size());
+  for (size_t i = 0; i < sized_array.size(); i++) {
+    ASSERT_EQ(array[i].data, sized_array[i].data);
+  }
+}
+
 vector<uint8_t> fixed_array_variable{
     0x03, 'o', 'n', 'e',            // "one"
     0x03, 't', 'w', 'o',            // "two"
@@ -682,6 +750,31 @@
   }
 }
 
+vector<uint8_t> fixed_array_variable_too_short{
+    0x03, 'o', 'n', 'e',            // "one"
+    0x03, 't', 'w', 'o',            // "two"
+    0x05, 't', 'h', 'r', 'e', 'e',  // "three"
+    0x04, 'f', 'o', 'u', 'r',       // "four"
+    0x05, 'f', 'i', 'v', 'e',       // "five"
+};
+
+TEST(GeneratedPacketTest, testFixedArrayVariableLengthTooShort) {
+  std::array<Variable, 5> fixed_array{std::string("one"), std::string("two"), std::string("three"),
+                                      std::string("four")};
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(fixed_array_variable_too_short);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = FixedArrayVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetVariableArray();
+  ASSERT_EQ(fixed_array.size(), array.size());
+  for (size_t i = 0; i < fixed_array.size(); i++) {
+    ASSERT_EQ(array[i].data, fixed_array[i].data);
+  }
+}
+
 vector<uint8_t> count_array_variable{
     0x04,                           // _count_
     0x03, 'o', 'n', 'e',            // "one"
@@ -719,6 +812,61 @@
   }
 }
 
+vector<uint8_t> count_array_variable_extra{
+    0x04,                           // _count_
+    0x03, 'o', 'n', 'e',            // "one"
+    0x03, 't', 'w', 'o',            // "two"
+    0x05, 't', 'h', 'r', 'e', 'e',  // "three"
+    0x04, 'f', 'o', 'u', 'r',       // "four"
+    0x04, 'x', 't', 'r', 'a',       // "xtra"
+};
+
+TEST(GeneratedPacketTest, testCountArrayVariableLengthExtraData) {
+  std::vector<Variable> count_array;
+  count_array.emplace_back("one");
+  count_array.emplace_back("two");
+  count_array.emplace_back("three");
+  count_array.emplace_back("four");
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(count_array_variable_extra);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = CountArrayVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetVariableArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].data, count_array[i].data);
+  }
+}
+
+vector<uint8_t> count_array_variable_too_few{
+    0x04,                           // _count_
+    0x03, 'o', 'n', 'e',            // "one"
+    0x03, 't', 'w', 'o',            // "two"
+    0x05, 't', 'h', 'r', 'e', 'e',  // "three"
+};
+
+TEST(GeneratedPacketTest, testCountArrayVariableLengthMissingData) {
+  std::vector<Variable> count_array;
+  count_array.emplace_back("one");
+  count_array.emplace_back("two");
+  count_array.emplace_back("three");
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(count_array_variable_too_few);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = CountArrayVariableView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetVariableArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].data, count_array[i].data);
+  }
+}
+
 vector<uint8_t> one_struct{
     0x01, 0x02, 0x03,  // id = 0x01, count = 0x0302
 };
@@ -731,6 +879,10 @@
   auto packet = OneStructBuilder::Create(trn);
   ASSERT_EQ(one_struct.size(), packet->size());
 
+  // Copy the original struct, then modify it to verify independence from the packet.
+  TwoRelatedNumbers copy_trn(trn);
+  trn.id_ = 2;
+
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter it(*packet_bytes);
   packet->Serialize(it);
@@ -744,8 +896,8 @@
   auto view = OneStructView::Create(packet_bytes_view);
   ASSERT_TRUE(view.IsValid());
   auto one = view.GetOne();
-  ASSERT_EQ(one.id_, trn.id_);
-  ASSERT_EQ(one.count_, trn.count_);
+  ASSERT_EQ(one.id_, copy_trn.id_);
+  ASSERT_EQ(one.count_, copy_trn.count_);
 }
 
 vector<uint8_t> two_structs{
@@ -785,13 +937,13 @@
   ASSERT_EQ(two.count_, count_array[1].count_);
 }
 
-vector<uint8_t> array_of_struct{
+vector<uint8_t> array_or_vector_of_struct{
     0x04,              // _count_
     0x01, 0x01, 0x02,  // id, id * 0x0201
     0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
 };
 
-TEST(GeneratedPacketTest, testArrayOfStruct) {
+TEST(GeneratedPacketTest, testVectorOfStruct) {
   std::vector<TwoRelatedNumbers> count_array;
   for (uint8_t i = 1; i < 5; i++) {
     TwoRelatedNumbers trn;
@@ -800,26 +952,72 @@
     count_array.push_back(trn);
   }
 
-  auto packet = ArrayOfStructBuilder::Create(count_array);
-  ASSERT_EQ(array_of_struct.size(), packet->size());
+  // Make a copy
+  std::vector<TwoRelatedNumbers> copy_array(count_array);
+
+  auto packet = VectorOfStructBuilder::Create(count_array);
+
+  // Change the original vector to make sure a copy was made.
+  count_array[0].id_ = count_array[0].id_ + 1;
+
+  ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
 
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter it(*packet_bytes);
   packet->Serialize(it);
 
-  ASSERT_EQ(array_of_struct.size(), packet_bytes->size());
-  for (size_t i = 0; i < array_of_struct.size(); i++) {
-    ASSERT_EQ(array_of_struct[i], packet_bytes->at(i));
+  ASSERT_EQ(array_or_vector_of_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_or_vector_of_struct.size(); i++) {
+    ASSERT_EQ(array_or_vector_of_struct[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = VectorOfStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(copy_array.size(), array.size());
+  for (size_t i = 0; i < copy_array.size(); i++) {
+    ASSERT_EQ(array[i].id_, copy_array[i].id_);
+    ASSERT_EQ(array[i].count_, copy_array[i].count_);
+  }
+}
+
+TEST(GeneratedPacketTest, testArrayOfStruct) {
+  std::array<TwoRelatedNumbers, 4> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    TwoRelatedNumbers trn;
+    trn.id_ = i;
+    trn.count_ = 0x0201 * i;
+    count_array[i - 1] = trn;
+  }
+
+  // Make a copy
+  std::array<TwoRelatedNumbers, 4> copy_array(count_array);
+
+  auto packet = ArrayOfStructBuilder::Create(4, count_array);
+
+  // Change the original vector to make sure a copy was made.
+  count_array[0].id_ = count_array[0].id_ + 1;
+
+  ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(array_or_vector_of_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_or_vector_of_struct.size(); i++) {
+    ASSERT_EQ(array_or_vector_of_struct[i], packet_bytes->at(i));
   }
 
   PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
   auto view = ArrayOfStructView::Create(packet_bytes_view);
   ASSERT_TRUE(view.IsValid());
   auto array = view.GetArray();
-  ASSERT_EQ(count_array.size(), array.size());
-  for (size_t i = 0; i < count_array.size(); i++) {
-    ASSERT_EQ(array[i].id_, count_array[i].id_);
-    ASSERT_EQ(array[i].count_, count_array[i].count_);
+  ASSERT_EQ(copy_array.size(), array.size());
+  for (size_t i = 0; i < copy_array.size(); i++) {
+    ASSERT_EQ(array[i].id_, copy_array[i].id_);
+    ASSERT_EQ(array[i].count_, copy_array[i].count_);
   }
 }
 
@@ -882,7 +1080,7 @@
   another.count_ = 0x0201 * 4;
 
   auto packet = ArrayOfStructAndAnotherBuilder::Create(count_array, another);
-  ASSERT_EQ(array_of_struct.size(), packet->size());
+  ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
 
   std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
   BitInserter it(*packet_bytes);
@@ -907,6 +1105,31 @@
   ASSERT_EQ(nother.count_, another.count_);
 }
 
+DEFINE_AND_INSTANTIATE_OneArrayOfStructAndAnotherStructReflectionTest(array_of_struct_and_another);
+
+TEST(GeneratedPacketTest, testOneArrayOfStructAndAnotherStruct) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(array_of_struct_and_another);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneArrayOfStructAndAnotherStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one.array_.size(), 3);
+  ASSERT_EQ(one.another_.id_, 4);
+  ASSERT_EQ(one.another_.count_, 0x0804);
+}
+
+vector<uint8_t> sized_array_of_struct_and_another{
+    0x09,              // _size_
+    0x01, 0x01, 0x02,  // id, id * 0x0201
+    0x02, 0x02, 0x04,  // 2
+    0x03, 0x03, 0x06,  // 3
+    0x04, 0x04, 0x08,  // Another
+};
+
+DEFINE_AND_INSTANTIATE_OneSizedArrayOfStructAndAnotherStructReflectionTest(sized_array_of_struct_and_another);
+
 vector<uint8_t> bit_field_group_packet{
     // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
     0xf7,  // 0x77 | (0x5 & 0x1) << 7
@@ -1117,6 +1340,491 @@
   }
 }
 
+TEST(GeneratedPacketTest, testNewBitFieldArrayPacket) {
+  PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(bit_field_array_packet));
+  auto view = BitFieldArrayPacketView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+
+  auto packet = BitFieldArrayPacketBuilder::Create(view.GetArray());
+  ASSERT_EQ(bit_field_array_packet.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(*packet_bytes, bit_field_array_packet);
+}
+
+std::vector<uint8_t> child_two_two_two_ = {0x20, 0x02};
+std::vector<uint8_t> child_two_two_three_ = {0x20, 0x03};
+std::vector<uint8_t> child_two_two_four_ = {0x20, 0x04};
+
+DEFINE_AND_INSTANTIATE_ParentTwoReflectionTest(child_two_two_two_, child_two_two_three_, child_two_two_four_);
+
+DEFINE_AND_INSTANTIATE_ChildTwoTwoReflectionTest(child_two_two_two_, child_two_two_three_, child_two_two_four_);
+
+DEFINE_AND_INSTANTIATE_ChildTwoTwoThreeReflectionTest(child_two_two_three_);
+
+std::vector<uint8_t> one_versionless_struct_packet = {0x01};
+std::vector<uint8_t> one_versioned_struct_packet = {0x02, 0x03 /* version */, 0x04, 0x05, 0x06};
+std::vector<uint8_t> one_version_one_struct_packet = {0x03, 0x01 /* version */, 0x02};
+std::vector<uint8_t> one_version_two_struct_packet = {0x03, 0x02 /* version */, 0x03, 0x04};
+DEFINE_AND_INSTANTIATE_OneVersionlessStructPacketReflectionTest(one_versionless_struct_packet,
+                                                                one_versioned_struct_packet,
+                                                                one_version_one_struct_packet,
+                                                                one_version_two_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionedStructPacketReflectionTest(one_versioned_struct_packet,
+                                                              one_version_one_struct_packet,
+                                                              one_version_two_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionOneStructPacketReflectionTest(one_version_one_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionTwoStructPacketReflectionTest(one_version_two_struct_packet);
+
+vector<uint8_t> one_struct_be{
+    0x01, 0x02, 0x03,  // id = 0x01, count = 0x0203
+};
+
+TEST(GeneratedPacketTest, testOneStructBe) {
+  TwoRelatedNumbersBe trn;
+  trn.id_ = 1;
+  trn.count_ = 0x0203;
+
+  auto packet = OneStructBeBuilder::Create(trn);
+  ASSERT_EQ(one_struct_be.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_struct_be.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_struct_be.size(); i++) {
+    ASSERT_EQ(one_struct_be[i], packet_bytes->at(i));
+  }
+
+  PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneStructBeView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one.id_, trn.id_);
+  ASSERT_EQ(one.count_, trn.count_);
+}
+
+vector<uint8_t> two_structs_be{
+    0x01, 0x01, 0x02,  // id, id * 0x0102
+    0x02, 0x02, 0x04,
+};
+
+TEST(GeneratedPacketTest, testTwoStructsBe) {
+  std::vector<TwoRelatedNumbersBe> count_array;
+  for (uint8_t i = 1; i < 3; i++) {
+    TwoRelatedNumbersBe trn;
+    trn.id_ = i;
+    trn.count_ = 0x0102 * i;
+    count_array.push_back(trn);
+  }
+
+  auto packet = TwoStructsBeBuilder::Create(count_array[0], count_array[1]);
+  ASSERT_EQ(two_structs_be.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(two_structs_be.size(), packet_bytes->size());
+  for (size_t i = 0; i < two_structs_be.size(); i++) {
+    ASSERT_EQ(two_structs_be[i], packet_bytes->at(i));
+  }
+
+  PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = TwoStructsBeView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOne();
+  ASSERT_EQ(one.id_, count_array[0].id_);
+  ASSERT_EQ(one.count_, count_array[0].count_);
+  auto two = view.GetTwo();
+  ASSERT_EQ(two.id_, count_array[1].id_);
+  ASSERT_EQ(two.count_, count_array[1].count_);
+}
+
+vector<uint8_t> array_of_struct_be{
+    0x04,              // _count_
+    0x01, 0x01, 0x02,  // id, id * 0x0102
+    0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
+};
+
+TEST(GeneratedPacketTest, testArrayOfStructBe) {
+  std::vector<TwoRelatedNumbersBe> count_array;
+  for (uint8_t i = 1; i < 5; i++) {
+    TwoRelatedNumbersBe trn;
+    trn.id_ = i;
+    trn.count_ = 0x0102 * i;
+    count_array.push_back(trn);
+  }
+
+  auto packet = ArrayOfStructBeBuilder::Create(count_array);
+
+  ASSERT_EQ(array_of_struct_be.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(array_of_struct_be.size(), packet_bytes->size());
+  for (size_t i = 0; i < array_of_struct_be.size(); i++) {
+    ASSERT_EQ(array_of_struct_be[i], packet_bytes->at(i));
+  }
+
+  PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = ArrayOfStructBeView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto array = view.GetArray();
+  ASSERT_EQ(count_array.size(), array.size());
+  for (size_t i = 0; i < count_array.size(); i++) {
+    ASSERT_EQ(array[i].id_, count_array[i].id_);
+    ASSERT_EQ(array[i].count_, count_array[i].count_);
+  }
+}
+
+vector<uint8_t> one_four_byte_struct{
+    0x04,                    // struct_type_ = FourByte
+    0xd1, 0xd2, 0xd3, 0xd4,  // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneFourByteStruct) {
+  FourByteStruct four_byte_struct;
+  four_byte_struct.four_bytes_ = 0xd4d3d2d1;
+
+  auto packet = OneFourByteStructBuilder::Create(four_byte_struct);
+  ASSERT_EQ(one_four_byte_struct.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_four_byte_struct.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_four_byte_struct.size(); i++) {
+    ASSERT_EQ(one_four_byte_struct[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneFourByteStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  ASSERT_EQ(StructType::FOUR_BYTE, view.GetOneStruct().struct_type_);
+  ASSERT_EQ(four_byte_struct.four_bytes_, view.GetOneStruct().four_bytes_);
+}
+
+vector<uint8_t> generic_struct_two{
+    0x02,        // struct_type_ = TwoByte
+    0x01, 0x02,  // two_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructTwo) {
+  TwoByteStruct two_byte_struct;
+  two_byte_struct.two_bytes_ = 0x0201;
+  std::unique_ptr<TwoByteStruct> two_byte_struct_ptr = std::make_unique<TwoByteStruct>(two_byte_struct);
+
+  auto packet = OneGenericStructBuilder::Create(std::move(two_byte_struct_ptr));
+  ASSERT_EQ(generic_struct_two.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(generic_struct_two.size(), packet_bytes->size());
+  for (size_t i = 0; i < generic_struct_two.size(); i++) {
+    ASSERT_EQ(generic_struct_two[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneGenericStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto base_struct = view.GetBaseStruct();
+  ASSERT_NE(nullptr, base_struct);
+  ASSERT_TRUE(TwoByteStruct::IsInstance(*base_struct));
+  TwoByteStruct* two_byte = static_cast<TwoByteStruct*>(base_struct.get());
+  ASSERT_NE(nullptr, two_byte);
+  ASSERT_TRUE(TwoByteStruct::IsInstance(*two_byte));
+  ASSERT_EQ(two_byte_struct.two_bytes_, 0x0201);
+  uint16_t val = two_byte->two_bytes_;
+  ASSERT_EQ(val, 0x0201);
+  ASSERT_EQ(two_byte_struct.two_bytes_, ((TwoByteStruct*)base_struct.get())->two_bytes_);
+}
+
+vector<uint8_t> generic_struct_four{
+    0x04,                    // struct_type_ = FourByte
+    0x01, 0x02, 0x03, 0x04,  // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructFour) {
+  FourByteStruct four_byte_struct;
+  four_byte_struct.four_bytes_ = 0x04030201;
+  std::unique_ptr<FourByteStruct> four_byte_struct_p = std::make_unique<FourByteStruct>(four_byte_struct);
+  ASSERT_EQ(four_byte_struct.four_bytes_, four_byte_struct_p->four_bytes_);
+
+  auto packet = OneGenericStructBuilder::Create(std::move(four_byte_struct_p));
+  ASSERT_EQ(generic_struct_four.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(generic_struct_four.size(), packet_bytes->size());
+  for (size_t i = 0; i < generic_struct_four.size(); i++) {
+    ASSERT_EQ(generic_struct_four[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneGenericStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto base_struct = view.GetBaseStruct();
+  ASSERT_NE(nullptr, base_struct);
+  ASSERT_EQ(StructType::FOUR_BYTE, base_struct->struct_type_);
+  ASSERT_EQ(four_byte_struct.four_bytes_, ((FourByteStruct*)base_struct.get())->four_bytes_);
+}
+
+vector<uint8_t> one_struct_array{
+    0x04,                    // struct_type_ = FourByte
+    0xa1, 0xa2, 0xa3, 0xa4,  // four_bytes_
+    0x04,                    // struct_type_ = FourByte
+    0xb2, 0xb2, 0xb3, 0xb4,  // four_bytes_
+    0x02,                    // struct_type_ = TwoByte
+    0xc3, 0xc2,              // two_bytes_
+    0x04,                    // struct_type_ = TwoByte
+    0xd4, 0xd2, 0xd3, 0xd4,  // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructArray) {
+  std::vector<std::unique_ptr<UnusedParentStruct>> parent_vector;
+  std::unique_ptr<FourByteStruct> fbs;
+  std::unique_ptr<TwoByteStruct> tbs;
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xa4a3a2a1;
+  parent_vector.push_back(std::move(fbs));
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xb4b3b2b2;
+  parent_vector.push_back(std::move(fbs));
+  tbs = std::make_unique<TwoByteStruct>();
+  tbs->two_bytes_ = 0xc2c3;
+  parent_vector.push_back(std::move(tbs));
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xd4d3d2d4;
+  parent_vector.push_back(std::move(fbs));
+
+  std::vector<std::unique_ptr<UnusedParentStruct>> vector_copy;
+  for (auto& s : parent_vector) {
+    if (s->struct_type_ == StructType::TWO_BYTE) {
+      vector_copy.push_back(std::make_unique<TwoByteStruct>(*(TwoByteStruct*)s.get()));
+    }
+    if (s->struct_type_ == StructType::FOUR_BYTE) {
+      vector_copy.push_back(std::make_unique<FourByteStruct>(*(FourByteStruct*)s.get()));
+    }
+  }
+
+  auto packet = OneGenericStructArrayBuilder::Create(std::move(parent_vector));
+  ASSERT_EQ(one_struct_array.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_struct_array.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_struct_array.size(); i++) {
+    ASSERT_EQ(one_struct_array[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneGenericStructArrayView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto an_array = view.GetAnArray();
+  ASSERT_EQ(vector_copy.size(), an_array.size());
+  for (size_t i = 0; i < vector_copy.size(); i++) {
+    ASSERT_NE(nullptr, an_array[i]);
+    ASSERT_EQ(vector_copy[i]->struct_type_, an_array[i]->struct_type_);
+    if (vector_copy[i]->struct_type_ == StructType::FOUR_BYTE) {
+      ASSERT_EQ(FourByteStruct::Specialize(vector_copy[i].get())->four_bytes_,
+                FourByteStruct::Specialize(an_array[i].get())->four_bytes_);
+    } else {
+      ASSERT_EQ(TwoByteStruct::Specialize(vector_copy[i].get())->two_bytes_,
+                TwoByteStruct::Specialize(an_array[i].get())->two_bytes_);
+    }
+  }
+}
+
+TEST(GeneratedPacketTest, testOneGenericStructFourArray) {
+  std::array<std::unique_ptr<UnusedParentStruct>, 4> parent_vector;
+  std::unique_ptr<FourByteStruct> fbs;
+  std::unique_ptr<TwoByteStruct> tbs;
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xa4a3a2a1;
+  parent_vector[0] = std::move(fbs);
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xb4b3b2b2;
+  parent_vector[1] = std::move(fbs);
+  tbs = std::make_unique<TwoByteStruct>();
+  tbs->two_bytes_ = 0xc2c3;
+  parent_vector[2] = std::move(tbs);
+  fbs = std::make_unique<FourByteStruct>();
+  fbs->four_bytes_ = 0xd4d3d2d4;
+  parent_vector[3] = std::move(fbs);
+
+  std::array<std::unique_ptr<UnusedParentStruct>, 4> vector_copy;
+  size_t i = 0;
+  for (auto& s : parent_vector) {
+    if (s->struct_type_ == StructType::TWO_BYTE) {
+      vector_copy[i] = std::make_unique<TwoByteStruct>(*(TwoByteStruct*)s.get());
+    }
+    if (s->struct_type_ == StructType::FOUR_BYTE) {
+      vector_copy[i] = std::make_unique<FourByteStruct>(*(FourByteStruct*)s.get());
+    }
+    i++;
+  }
+
+  auto packet = OneGenericStructFourArrayBuilder::Create(std::move(parent_vector));
+  ASSERT_EQ(one_struct_array.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_struct_array.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_struct_array.size(); i++) {
+    ASSERT_EQ(one_struct_array[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneGenericStructFourArrayView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto an_array = view.GetAnArray();
+  ASSERT_EQ(vector_copy.size(), an_array.size());
+  for (size_t i = 0; i < vector_copy.size(); i++) {
+    ASSERT_NE(nullptr, an_array[i]);
+    ASSERT_EQ(vector_copy[i]->struct_type_, an_array[i]->struct_type_);
+    if (vector_copy[i]->struct_type_ == StructType::FOUR_BYTE) {
+      ASSERT_EQ(FourByteStruct::Specialize(vector_copy[i].get())->four_bytes_,
+                FourByteStruct::Specialize(an_array[i].get())->four_bytes_);
+    } else {
+      ASSERT_EQ(TwoByteStruct::Specialize(vector_copy[i].get())->two_bytes_,
+                TwoByteStruct::Specialize(an_array[i].get())->two_bytes_);
+    }
+  }
+}
+
+vector<uint8_t> one_struct_array_after_fixed{
+    0x01, 0x02,              // two_bytes = 0x0201
+    0x04,                    // struct_type_ = FourByte
+    0xa1, 0xa2, 0xa3, 0xa4,  // four_bytes_
+    0x04,                    // struct_type_ = FourByte
+    0xb2, 0xb2, 0xb3, 0xb4,  // four_bytes_
+    0x02,                    // struct_type_ = TwoByte
+    0xc3, 0xc2,              // two_bytes_
+    0x04,                    // struct_type_ = TwoByte
+    0xd4, 0xd2, 0xd3, 0xd4,  // four_bytes_
+};
+
+DEFINE_AND_INSTANTIATE_OneGenericStructArrayAfterFixedReflectionTest(one_struct_array_after_fixed);
+
+vector<uint8_t> one_length_type_value_struct{
+    // _size_(value):16 type value
+    0x04, 0x00, 0x01, 'o', 'n', 'e',            // ONE
+    0x04, 0x00, 0x02, 't', 'w', 'o',            // TWO
+    0x06, 0x00, 0x03, 't', 'h', 'r', 'e', 'e',  // THREE
+};
+
+DEFINE_AND_INSTANTIATE_OneLengthTypeValueStructReflectionTest(one_length_type_value_struct);
+
+TEST(GeneratedPacketTest, testOneLengthTypeValueStruct) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+      std::make_shared<std::vector<uint8_t>>(one_length_type_value_struct);
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneLengthTypeValueStructView::Create(packet_bytes_view);
+  ASSERT_TRUE(view.IsValid());
+  auto one = view.GetOneArray();
+  size_t entry_id = 0;
+  for (const auto& entry : one) {
+    switch (entry_id++) {
+      case 0:
+        ASSERT_EQ(entry.type_, DataType::ONE);
+        ASSERT_EQ(entry.value_, std::vector<uint8_t>({'o', 'n', 'e'}));
+        break;
+      case 1:
+        ASSERT_EQ(entry.type_, DataType::TWO);
+        ASSERT_EQ(entry.value_, std::vector<uint8_t>({'t', 'w', 'o'}));
+        break;
+      case 2:
+        ASSERT_EQ(entry.type_, DataType::THREE);
+        ASSERT_EQ(entry.value_, std::vector<uint8_t>({'t', 'h', 'r', 'e', 'e'}));
+        break;
+      default:
+        ASSERT_EQ(entry.type_, DataType::UNUSED);
+    }
+  }
+}
+
+vector<uint8_t> one_length_type_value_struct_padded_20{
+    0x27,  // _size_(payload),
+    // _size_(value):16 type value
+    0x04, 0x00, 0x01, 'o', 'n', 'e',                             // ONE
+    0x04, 0x00, 0x02, 't', 'w', 'o',                             // TWO
+    0x06, 0x00, 0x03, 't', 'h', 'r', 'e', 'e',                   // THREE
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,        // padding to 30
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // padding to 40
+};
+
+vector<uint8_t> one_length_type_value_struct_padded_28{
+    0x27,  // _size_(payload),
+    // _size_(value):16 type value
+    0x04, 0x00, 0x01, 'o', 'n', 'e',                             // ONE
+    0x04, 0x00, 0x02, 't', 'w', 'o',                             // TWO
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                    // padding to 20
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // padding to 30
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // padding to 40
+};
+
+// TODO: Revisit LTV parsing.  Right now, the padding bytes are parsed
+// DEFINE_AND_INSTANTIATE_OneLengthTypeValueStructPaddedReflectionTest(one_length_type_value_struct_padded_20,
+// one_length_type_value_struct_padded_28);
+
+TEST(GeneratedPacketTest, testOneLengthTypeValueStructPaddedGeneration) {
+  std::vector<LengthTypeValueStruct> ltv_vector;
+  LengthTypeValueStruct ltv;
+  ltv.type_ = DataType::ONE;
+  ltv.value_ = {
+      'o',
+      'n',
+      'e',
+  };
+  ltv_vector.push_back(ltv);
+  ltv.type_ = DataType::TWO;
+  ltv.value_ = {
+      't',
+      'w',
+      'o',
+  };
+  ltv_vector.push_back(ltv);
+
+  auto packet = OneLengthTypeValueStructPaddedBuilder::Create(ltv_vector);
+  ASSERT_EQ(one_length_type_value_struct_padded_28.size(), packet->size());
+
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  packet->Serialize(it);
+
+  ASSERT_EQ(one_length_type_value_struct_padded_28.size(), packet_bytes->size());
+  for (size_t i = 0; i < one_length_type_value_struct_padded_28.size(); i++) {
+    ASSERT_EQ(one_length_type_value_struct_padded_28[i], packet_bytes->at(i));
+  }
+
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto view = OneLengthTypeValueStructPaddedView::Create(SizedParentView::Create(packet_bytes_view));
+  ASSERT_TRUE(view.IsValid());
+  auto an_array = view.GetOneArray();
+  // TODO: Revisit LTV parsing.  Right now, the padding bytes are parsed
+  // ASSERT_EQ(ltv_vector.size(), an_array.size());
+  for (size_t i = 0; i < ltv_vector.size(); i++) {
+    ASSERT_EQ(ltv_vector[i].type_, an_array[i].type_);
+    ASSERT_EQ(ltv_vector[i].value_, an_array[i].value_);
+  }
+}
 }  // namespace parser
 }  // namespace packet
 }  // namespace bluetooth
diff --git a/gd/packet/parser/test/test_packets.pdl b/gd/packet/parser/test/test_packets.pdl
index 4ed0f0c..3c24509 100644
--- a/gd/packet/parser/test/test_packets.pdl
+++ b/gd/packet/parser/test/test_packets.pdl
@@ -180,11 +180,16 @@
   two : TwoRelatedNumbers,
 }
 
-packet ArrayOfStruct {
+packet VectorOfStruct {
   _count_(array) : 8,
   array : TwoRelatedNumbers[],
 }
 
+packet ArrayOfStruct {
+  the_count : 8,
+  array : TwoRelatedNumbers[4],
+}
+
 struct StructWithFixedTypes {
   four_bits : FourBits,
   _reserved_ : 4,
@@ -206,6 +211,32 @@
   another : TwoRelatedNumbers,
 }
 
+packet SizedArrayOfStructAndAnother {
+  _size_(array) : 8,
+  array : TwoRelatedNumbers[],
+  another : TwoRelatedNumbers,
+}
+
+struct ArrayOfStructAndAnotherStruct {
+  _count_(array) : 8,
+  array : TwoRelatedNumbers[],
+  another : TwoRelatedNumbers,
+}
+
+struct SizedArrayOfStructAndAnotherStruct {
+  _size_(array) : 8,
+  array : TwoRelatedNumbers[],
+  another : TwoRelatedNumbers,
+}
+
+packet OneArrayOfStructAndAnotherStruct {
+  one : ArrayOfStructAndAnotherStruct,
+}
+
+packet OneSizedArrayOfStructAndAnotherStruct {
+  one : SizedArrayOfStructAndAnotherStruct,
+}
+
 group BitFieldGroup {
   seven_bits : 7,
   straddle : 4,
@@ -248,3 +279,118 @@
   _size_(array): 8,
   array : BitField[],
 }
+
+struct VersionlessStruct {
+  one_number : 8,
+}
+
+packet OneVersionlessStructPacket {
+  versionless : VersionlessStruct,
+  _payload_,
+}
+
+packet OneVersionedStructPacket : OneVersionlessStructPacket {
+  version : 8,
+  _payload_,
+}
+
+packet OneVersionOneStructPacket : OneVersionedStructPacket(version = 0x01) {
+  just_one_number : 8,
+}
+
+packet OneVersionTwoStructPacket : OneVersionedStructPacket(version = 0x02) {
+  one_number : 8,
+  another_number : 8,
+}
+
+enum StructType : 8 {
+  ZERO_BYTE = 0x00,
+  TWO_BYTE = 0x02,
+  FOUR_BYTE = 0x04,
+  AT_LEAST_FOUR_BYTE = 0x05,
+  VARIABLE = 0x06,
+}
+
+struct UnusedParentStruct {
+  struct_type : StructType,
+  _body_,
+}
+
+struct TwoByteStruct : UnusedParentStruct (struct_type = TWO_BYTE) {
+  two_bytes : 16,
+}
+
+struct FourByteStruct : UnusedParentStruct (struct_type = FOUR_BYTE) {
+  four_bytes : 32,
+}
+
+struct AtLeastFourByteStruct : UnusedParentStruct (struct_type = AT_LEAST_FOUR_BYTE) {
+  four_bytes : 32,
+  struct_type : StructType,
+  _body_,
+}
+
+struct OnlyFourByteStruct : AtLeastFourByteStruct (struct_type = ZERO_BYTE) {
+}
+
+struct SixByteStruct : AtLeastFourByteStruct (struct_type = TWO_BYTE) {
+  two_bytes : 16,
+}
+
+struct EightByteStruct : AtLeastFourByteStruct (struct_type = FOUR_BYTE) {
+  four_bytes : 32,
+}
+
+packet OneFourByteStruct {
+  one_struct : FourByteStruct,
+}
+
+packet OneGenericStruct {
+  base_struct : UnusedParentStruct,
+}
+
+packet OneGenericStructArray {
+  an_array : UnusedParentStruct[],
+}
+
+packet OneGenericStructFourArray {
+  an_array : UnusedParentStruct[4],
+}
+
+packet ParentWithOnlyFixed {
+  two_bytes : 16,
+  _body_,
+}
+
+packet OneGenericStructArrayAfterFixed : ParentWithOnlyFixed {
+  an_array : UnusedParentStruct[],
+}
+
+enum DataType : 8 {
+  ONE = 0x01,
+  TWO = 0x02,
+  THREE = 0x03,
+  FOUR = 0x04,
+  FIVE = 0x05,
+  UNUSED = 0x06,
+}
+
+struct LengthTypeValueStruct {
+  _size_(value) : 16,
+  type : DataType,
+  value : 8[+1*8],
+}
+
+packet OneLengthTypeValueStruct {
+  one_array : LengthTypeValueStruct[],
+}
+
+packet SizedParent {
+  _size_(payload) : 8,
+  _payload_,
+}
+
+packet OneLengthTypeValueStructPadded : SizedParent {
+  one_array : LengthTypeValueStruct[],
+  _padding_[40],
+}
diff --git a/gd/packet/parser/test/variable.cc b/gd/packet/parser/test/variable.cc
index b359ed3..23443bf 100644
--- a/gd/packet/parser/test/variable.cc
+++ b/gd/packet/parser/test/variable.cc
@@ -42,25 +42,6 @@
 size_t Variable::size() const {
   return data.size() + 1;
 }
-
-Iterator<true> Variable::Parse(std::vector<Variable>& vec, Iterator<true> it) {
-  if (it.NumBytesRemaining() < 1) {
-    return it;
-  }
-  size_t data_length = it.extract<uint8_t>();
-  if (data_length > 255) {
-    return it + it.NumBytesRemaining();
-  }
-  if (it.NumBytesRemaining() < data_length) {
-    return it + it.NumBytesRemaining();
-  }
-  std::stringstream ss;
-  for (size_t i = 0; i < data_length; i++) {
-    ss << it.extract<char>();
-  }
-  vec.emplace_back(ss.str());
-  return it;
-}
 }  // namespace test
 }  // namespace parser
 }  // namespace packet
diff --git a/gd/packet/parser/test/variable.h b/gd/packet/parser/test/variable.h
index 056eac6..c452a37 100644
--- a/gd/packet/parser/test/variable.h
+++ b/gd/packet/parser/test/variable.h
@@ -43,30 +43,26 @@
 
   size_t size() const;
 
-  static Iterator<true> Parse(std::vector<Variable>& vec, Iterator<true> it);
-  template <std::size_t arr_size>
-  static Iterator<true> ParseArray(std::array<Variable, arr_size>& arr, std::size_t* arr_idx, Iterator<true> it);
-};
-
-template <std::size_t arr_size>
-Iterator<true> Variable::ParseArray(std::array<Variable, arr_size>& arr, std::size_t* arr_idx, Iterator<true> it) {
-  if (it.NumBytesRemaining() < 1) {
+  template <bool little_endian>
+  static std::optional<Iterator<little_endian>> Parse(Variable* instance, Iterator<little_endian> it) {
+    if (it.NumBytesRemaining() < 1) {
+      return {};
+    }
+    size_t data_length = it.template extract<uint8_t>();
+    if (data_length > 255) {
+      return {};
+    }
+    if (it.NumBytesRemaining() < data_length) {
+      return {};
+    }
+    std::stringstream ss;
+    for (size_t i = 0; i < data_length; i++) {
+      ss << it.template extract<char>();
+    }
+    *instance = ss.str();
     return it;
   }
-  size_t data_length = it.extract<uint8_t>();
-  if (data_length > 255) {
-    return it + it.NumBytesRemaining();
-  }
-  if (it.NumBytesRemaining() < data_length) {
-    return it + it.NumBytesRemaining();
-  }
-  std::stringstream ss;
-  for (size_t i = 0; i < data_length; i++) {
-    ss << it.extract<char>();
-  }
-  arr[*arr_idx] = ss.str();
-  return it;
-}
+};
 
 }  // namespace test
 }  // namespace parser
diff --git a/gd/packet/parser/type_def.h b/gd/packet/parser/type_def.h
index e046e16..811dca8 100644
--- a/gd/packet/parser/type_def.h
+++ b/gd/packet/parser/type_def.h
@@ -19,7 +19,6 @@
 #include <iostream>
 
 #include "fields/packet_field.h"
-#include "fields/reserved_field.h"
 
 class TypeDef {
  public:
diff --git a/gd/packet/parser/util.h b/gd/packet/parser/util.h
index 4ae2d68..a8b881d 100644
--- a/gd/packet/parser/util.h
+++ b/gd/packet/parser/util.h
@@ -103,4 +103,35 @@
   return camel_case.str();
 }
 
+inline bool IsEnumCase(std::string value) {
+  if (value[0] < 'A' || value[0] > 'Z') {
+    return false;
+  }
+
+  // Use static to avoid compiling the regex more than once.
+  static const std::regex enum_regex("[A-Z][A-Z0-9_]*");
+
+  return std::regex_match(value, enum_regex);
+}
+
+inline std::string StringJoin(const std::string& delimiter, const std::vector<std::string>& vec) {
+  std::stringstream ss;
+  for (size_t i = 0; i < vec.size(); i++) {
+    ss << vec[i];
+    if (i != (vec.size() - 1)) {
+      ss << delimiter;
+    }
+  }
+  return ss.str();
+}
+
+inline std::string StringFindAndReplaceAll(std::string text, const std::string& old, const std::string& replacement) {
+  auto pos = text.find(old);
+  while (pos != std::string::npos) {
+    text.replace(pos, old.size(), replacement);
+    pos = text.find(old, pos + replacement.size());
+  }
+  return text;
+}
+
 }  // namespace util
diff --git a/gd/packet/python3_module.cc b/gd/packet/python3_module.cc
new file mode 100644
index 0000000..879732b
--- /dev/null
+++ b/gd/packet/python3_module.cc
@@ -0,0 +1,84 @@
+/*
+ * 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 <cstring>
+#include <memory>
+
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+#include "packet/base_packet_builder.h"
+#include "packet/bit_inserter.h"
+#include "packet/iterator.h"
+#include "packet/packet_builder.h"
+#include "packet/packet_struct.h"
+#include "packet/packet_view.h"
+#include "packet/parser/checksum_type_checker.h"
+#include "packet/parser/custom_type_checker.h"
+
+namespace py = pybind11;
+
+namespace bluetooth {
+
+namespace hci {
+void define_hci_packets_submodule(py::module&);
+}
+namespace l2cap {
+void define_l2cap_packets_submodule(py::module&);
+}
+namespace security {
+void define_smp_packets_submodule(py::module&);
+}
+
+namespace packet {
+
+using ::bluetooth::packet::BasePacketBuilder;
+using ::bluetooth::packet::BaseStruct;
+using ::bluetooth::packet::BitInserter;
+using ::bluetooth::packet::CustomTypeChecker;
+using ::bluetooth::packet::Iterator;
+using ::bluetooth::packet::kLittleEndian;
+using ::bluetooth::packet::PacketBuilder;
+using ::bluetooth::packet::PacketStruct;
+using ::bluetooth::packet::PacketView;
+using ::bluetooth::packet::parser::ChecksumTypeChecker;
+
+PYBIND11_MODULE(bluetooth_packets_python3, m) {
+  py::class_<BasePacketBuilder>(m, "BasePacketBuilder");
+  py::class_<PacketBuilder<kLittleEndian>, BasePacketBuilder>(m, "PacketBuilderLittleEndian");
+  py::class_<PacketBuilder<!kLittleEndian>, BasePacketBuilder>(m, "PacketBuilderBigEndian");
+  py::class_<BaseStruct>(m, "BaseStruct");
+  py::class_<PacketStruct<kLittleEndian>, BaseStruct>(m, "PacketStructLittleEndian");
+  py::class_<PacketStruct<!kLittleEndian>, BaseStruct>(m, "PacketStructBigEndian");
+  py::class_<Iterator<kLittleEndian>>(m, "IteratorLittleEndian");
+  py::class_<Iterator<!kLittleEndian>>(m, "IteratorBigEndian");
+  py::class_<PacketView<kLittleEndian>>(m, "PacketViewLittleEndian").def(py::init([](std::vector<uint8_t> bytes) {
+    // Make a copy
+    auto bytes_shared = std::make_shared<std::vector<uint8_t>>(bytes);
+    return std::make_unique<PacketView<kLittleEndian>>(bytes_shared);
+  }));
+  py::class_<PacketView<!kLittleEndian>>(m, "PacketViewBigEndian").def(py::init([](std::vector<uint8_t> bytes) {
+    // Make a copy
+    auto bytes_shared = std::make_shared<std::vector<uint8_t>>(bytes);
+    return std::make_unique<PacketView<!kLittleEndian>>(bytes_shared);
+  }));
+
+  bluetooth::hci::define_hci_packets_submodule(m);
+  bluetooth::l2cap::define_l2cap_packets_submodule(m);
+  bluetooth::security::define_smp_packets_submodule(m);
+}
+
+}  // namespace packet
+}  // namespace bluetooth
diff --git a/gd/packet/raw_builder.cc b/gd/packet/raw_builder.cc
index fd61417..ec5159b 100644
--- a/gd/packet/raw_builder.cc
+++ b/gd/packet/raw_builder.cc
@@ -20,13 +20,14 @@
 
 #include "os/log.h"
 
+using bluetooth::hci::Address;
 using std::vector;
-using bluetooth::common::Address;
 
 namespace bluetooth {
 namespace packet {
 
 RawBuilder::RawBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
+RawBuilder::RawBuilder(std::vector<uint8_t> vec) : max_bytes_(vec.size()), payload_(vec) {}
 
 bool RawBuilder::AddOctets(size_t octets, const vector<uint8_t>& bytes) {
   if (payload_.size() + octets > max_bytes_) return false;
diff --git a/gd/packet/raw_builder.h b/gd/packet/raw_builder.h
index 8f9edf5..9b0e959 100644
--- a/gd/packet/raw_builder.h
+++ b/gd/packet/raw_builder.h
@@ -19,7 +19,7 @@
 #include <cstdint>
 #include <vector>
 
-#include "common/address.h"
+#include "hci/address.h"
 #include "packet/bit_inserter.h"
 #include "packet/packet_builder.h"
 
@@ -30,6 +30,7 @@
  public:
   RawBuilder() = default;
   RawBuilder(size_t max_bytes);
+  RawBuilder(std::vector<uint8_t> vec);
   virtual ~RawBuilder() = default;
 
   virtual size_t size() const override;
@@ -38,7 +39,7 @@
 
   // Add |address| to the payload.  Return true if:
   // - the new size of the payload is still <= |max_bytes_|
-  bool AddAddress(const common::Address& address);
+  bool AddAddress(const hci::Address& address);
 
   // Return true if |num_bytes| can be added to the payload.
   bool CanAddOctets(size_t num_bytes) const;
diff --git a/gd/packet/raw_builder_unittest.cc b/gd/packet/raw_builder_unittest.cc
index 27cecd6..5210fb6 100644
--- a/gd/packet/raw_builder_unittest.cc
+++ b/gd/packet/raw_builder_unittest.cc
@@ -20,9 +20,9 @@
 #include <forward_list>
 #include <memory>
 
-#include "common/address.h"
+#include "hci/address.h"
 
-using bluetooth::common::Address;
+using bluetooth::hci::Address;
 using bluetooth::packet::BitInserter;
 using std::vector;
 
diff --git a/gd/packet/view.h b/gd/packet/view.h
index 4f3b508..3b8b679 100644
--- a/gd/packet/view.h
+++ b/gd/packet/view.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <memory>
 #include <vector>
 
 namespace bluetooth {
diff --git a/gd/security/Android.bp b/gd/security/Android.bp
new file mode 100644
index 0000000..7762461
--- /dev/null
+++ b/gd/security/Android.bp
@@ -0,0 +1,26 @@
+filegroup {
+    name: "BluetoothSecuritySources",
+    srcs: [
+        "ecc/multprecision.cc",
+        "ecc/p_256_ecc_pp.cc",
+        "ecdh_keys.cc",
+        "pairing_handler_le.cc",
+        "pairing_handler_le_legacy.cc",
+        "pairing_handler_le_secure_connections.cc",
+        "security_manager.cc",
+        "internal/security_manager_impl.cc",
+        "security_module.cc",
+        ":BluetoothSecurityChannelSources",
+    ],
+}
+
+filegroup {
+    name: "BluetoothSecurityTestSources",
+    srcs: [
+        "ecc/multipoint_test.cc",
+        "pairing_handler_le_unittest.cc",
+        "test/fake_l2cap_test.cc",
+        "test/pairing_handler_le_pair_test.cc",
+        ":BluetoothSecurityChannelTestSources",
+    ],
+}
diff --git a/gd/security/channel/Android.bp b/gd/security/channel/Android.bp
new file mode 100644
index 0000000..653902b
--- /dev/null
+++ b/gd/security/channel/Android.bp
@@ -0,0 +1,13 @@
+filegroup {
+    name: "BluetoothSecurityChannelSources",
+    srcs: [
+        "security_manager_channel.cc",
+    ]
+}
+
+filegroup {
+    name: "BluetoothSecurityChannelTestSources",
+    srcs: [
+        "security_manager_channel_unittest.cc",
+    ]
+}
diff --git a/gd/security/channel/security_manager_channel.cc b/gd/security/channel/security_manager_channel.cc
new file mode 100644
index 0000000..331bbec
--- /dev/null
+++ b/gd/security/channel/security_manager_channel.cc
@@ -0,0 +1,93 @@
+/******************************************************************************
+ *
+ *  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 "security_manager_channel.h"
+
+#include "security/smp_packets.h"
+
+using namespace bluetooth::hci;
+using namespace bluetooth::packet;
+using namespace bluetooth::security::channel;
+
+void SecurityManagerChannel::SendCommand(std::shared_ptr<hci::Device> device,
+                                         std::unique_ptr<SecurityCommandBuilder> command) {
+  hci_security_interface_->EnqueueCommand(
+      std::move(command), common::BindOnce(&SecurityManagerChannel::OnCommandComplete, common::Unretained(this)),
+      handler_);
+}
+
+void SecurityManagerChannel::OnCommandComplete(CommandCompleteView packet) {
+  ASSERT_LOG(packet.IsValid(), "Received invalid packet: %hx", packet.GetCommandOpCode());
+  // TODO(optedoblivion): Verify HCI commands
+}
+
+void SecurityManagerChannel::OnHciEventReceived(EventPacketView packet) {
+  ASSERT_LOG(listener_ != nullptr, "No listener set!");
+  std::shared_ptr<Device> device = nullptr;
+  auto event = EventPacketView::Create(std::move(packet));
+  ASSERT_LOG(event.IsValid(), "Received invalid packet");
+  const hci::EventCode code = event.GetEventCode();
+  switch (code) {
+    case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE:
+      listener_->OnChangeConnectionLinkKeyComplete(device,
+                                                   hci::ChangeConnectionLinkKeyCompleteView::Create(std::move(event)));
+      break;
+    case hci::EventCode::MASTER_LINK_KEY_COMPLETE:
+      listener_->OnMasterLinkKeyComplete(device, hci::MasterLinkKeyCompleteView::Create(std::move(event)));
+      break;
+    case hci::EventCode::PIN_CODE_REQUEST:
+      listener_->OnPinCodeRequest(device, hci::PinCodeRequestView::Create(std::move(event)));
+      break;
+    case hci::EventCode::LINK_KEY_REQUEST:
+      listener_->OnLinkKeyRequest(device, hci::LinkKeyRequestView::Create(std::move(event)));
+      break;
+    case hci::EventCode::LINK_KEY_NOTIFICATION:
+      listener_->OnLinkKeyNotification(device, hci::LinkKeyNotificationView::Create(std::move(event)));
+      break;
+    case hci::EventCode::IO_CAPABILITY_REQUEST:
+      listener_->OnIoCapabilityRequest(device, hci::IoCapabilityRequestView::Create(std::move(event)));
+      break;
+    case hci::EventCode::IO_CAPABILITY_RESPONSE:
+      listener_->OnIoCapabilityResponse(device, IoCapabilityResponseView::Create(std::move(event)));
+      break;
+    case hci::EventCode::SIMPLE_PAIRING_COMPLETE:
+      listener_->OnSimplePairingComplete(device, SimplePairingCompleteView::Create(std::move(event)));
+      break;
+    case hci::EventCode::RETURN_LINK_KEYS:
+      listener_->OnReturnLinkKeys(device, hci::ReturnLinkKeysView::Create(std::move(event)));
+      break;
+    case hci::EventCode::ENCRYPTION_CHANGE:
+      listener_->OnEncryptionChange(device, hci::EncryptionChangeView::Create(std::move(event)));
+      break;
+    case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE:
+      listener_->OnEncryptionKeyRefreshComplete(device,
+                                                hci::EncryptionKeyRefreshCompleteView::Create(std::move(event)));
+      break;
+    case hci::EventCode::REMOTE_OOB_DATA_REQUEST:
+      listener_->OnRemoteOobDataRequest(device, hci::RemoteOobDataRequestView::Create(std::move(event)));
+      break;
+    case hci::EventCode::USER_PASSKEY_NOTIFICATION:
+      listener_->OnUserPasskeyNotification(device, hci::UserPasskeyNotificationView::Create(std::move(event)));
+      break;
+    case hci::EventCode::KEYPRESS_NOTIFICATION:
+      listener_->OnKeypressNotification(device, hci::KeypressNotificationView::Create(std::move(event)));
+      break;
+    default:
+      ASSERT_LOG(false, "Invalid packet received: %hhx", code);
+      break;
+  }
+}
diff --git a/gd/security/channel/security_manager_channel.h b/gd/security/channel/security_manager_channel.h
new file mode 100644
index 0000000..02d0357
--- /dev/null
+++ b/gd/security/channel/security_manager_channel.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ *  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 <memory>
+#include <vector>
+
+#include "hci/classic_device.h"
+#include "hci/hci_layer.h"
+#include "hci/security_interface.h"
+#include "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+namespace channel {
+
+using hci::CommandCompleteView;
+using hci::EventPacketView;
+using hci::SecurityCommandBuilder;
+using hci::SecurityCommandView;
+
+/**
+ * Interface for listening to the channel for SMP commands.
+ */
+class ISecurityManagerChannelListener {
+ public:
+  virtual ~ISecurityManagerChannelListener() = default;
+
+  virtual void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+                                                 hci::ChangeConnectionLinkKeyCompleteView packet) = 0;
+  virtual void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) = 0;
+  virtual void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) = 0;
+  virtual void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) = 0;
+  virtual void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) = 0;
+  virtual void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet) = 0;
+  virtual void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet) = 0;
+  virtual void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet) = 0;
+  virtual void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet) = 0;
+  virtual void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet) = 0;
+  virtual void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device,
+                                              hci::EncryptionKeyRefreshCompleteView packet) = 0;
+  virtual void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet) = 0;
+  virtual void OnUserPasskeyNotification(std::shared_ptr<hci::Device> device,
+                                         hci::UserPasskeyNotificationView packet) = 0;
+  virtual void OnKeypressNotification(std::shared_ptr<hci::Device> device, hci::KeypressNotificationView packet) = 0;
+};
+
+/**
+ * Channel for consolidating traffic and making the transport agnostic.
+ */
+class SecurityManagerChannel {
+ public:
+  explicit SecurityManagerChannel(os::Handler* handler, hci::HciLayer* hci_layer)
+      : listener_(nullptr),
+        hci_security_interface_(hci_layer->GetSecurityInterface(
+            common::Bind(&SecurityManagerChannel::OnHciEventReceived, common::Unretained(this)), handler)),
+        handler_(handler) {}
+  ~SecurityManagerChannel() {
+    delete listener_;
+  }
+
+  /**
+   * Send a given SMP command over the SecurityManagerChannel
+   *
+   * @param device target where command will be sent
+   * @param command smp command to send
+   */
+  void SendCommand(std::shared_ptr<hci::Device> device, std::unique_ptr<SecurityCommandBuilder> command);
+
+  /**
+   * Sets the listener to listen for channel events
+   *
+   * @param listener the caller interested in events
+   */
+  void SetChannelListener(ISecurityManagerChannelListener* listener) {
+    listener_ = listener;
+  }
+
+  /**
+   * Called when an incoming HCI event happens
+   *
+   * @param event_packet
+   */
+  void OnHciEventReceived(EventPacketView packet);
+
+  /**
+   * Called when an HCI command is completed
+   *
+   * @param on_complete
+   */
+  void OnCommandComplete(CommandCompleteView packet);
+
+ private:
+  ISecurityManagerChannelListener* listener_;
+  hci::SecurityInterface* hci_security_interface_;
+  os::Handler* handler_;
+};
+
+}  // namespace channel
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/channel/security_manager_channel_unittest.cc b/gd/security/channel/security_manager_channel_unittest.cc
new file mode 100644
index 0000000..b111e7f
--- /dev/null
+++ b/gd/security/channel/security_manager_channel_unittest.cc
@@ -0,0 +1,558 @@
+/******************************************************************************
+ *
+ *  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 "security_manager_channel.h"
+
+#include <gtest/gtest.h>
+
+#include "hci/device.h"
+#include "hci/device_database.h"
+#include "hci/hci_packets.h"
+#include "packet/raw_builder.h"
+#include "security/smp_packets.h"
+#include "security/test/fake_hci_layer.h"
+
+namespace bluetooth {
+namespace security {
+namespace channel {
+namespace {
+
+using bluetooth::security::channel::SecurityManagerChannel;
+using hci::AuthenticationRequirements;
+using hci::CommandCompleteBuilder;
+using hci::Device;
+using hci::DeviceDatabase;
+using hci::IoCapabilityRequestReplyBuilder;
+using hci::IoCapabilityRequestView;
+using hci::OobDataPresent;
+using hci::OpCode;
+using os::Handler;
+using os::Thread;
+using packet::RawBuilder;
+
+static DeviceDatabase kDeviceDatabase;
+
+class SecurityManagerChannelCallback : public ISecurityManagerChannelListener {
+ public:
+  // HCI
+  bool receivedChangeConnectionLinkKeyComplete = false;
+  bool receivedMasterLinkKeyComplete = false;
+  bool receivedPinCodeRequest = false;
+  bool receivedLinkKeyRequest = false;
+  bool receivedLinkKeyNotification = false;
+  bool receivedIoCapabilityRequest = false;
+  bool receivedIoCapabilityResponse = false;
+  bool receivedSimplePairingComplete = false;
+  bool receivedReturnLinkKeys = false;
+  bool receivedEncryptionChange = false;
+  bool receivedEncryptionKeyRefreshComplete = false;
+  bool receivedRemoteOobDataRequest = false;
+  bool receivedUserPasskeyNotification = false;
+  bool receivedKeypressNotification = false;
+
+  void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+                                         hci::ChangeConnectionLinkKeyCompleteView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedChangeConnectionLinkKeyComplete = true;
+  }
+  void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedMasterLinkKeyComplete = true;
+  }
+  void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedPinCodeRequest = true;
+  }
+  void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedLinkKeyRequest = true;
+  }
+  void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedLinkKeyNotification = true;
+  }
+  void OnIoCapabilityRequest(std::shared_ptr<Device> device, hci::IoCapabilityRequestView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedIoCapabilityRequest = true;
+  }
+  void OnIoCapabilityResponse(std::shared_ptr<Device> device, hci::IoCapabilityResponseView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedIoCapabilityResponse = true;
+  }
+  void OnSimplePairingComplete(std::shared_ptr<Device> device, hci::SimplePairingCompleteView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedSimplePairingComplete = true;
+  }
+  void OnReturnLinkKeys(std::shared_ptr<Device> device, hci::ReturnLinkKeysView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedReturnLinkKeys = true;
+  }
+  void OnEncryptionChange(std::shared_ptr<Device> device, hci::EncryptionChangeView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedEncryptionChange = true;
+  }
+  void OnEncryptionKeyRefreshComplete(std::shared_ptr<Device> device, hci::EncryptionKeyRefreshCompleteView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedEncryptionKeyRefreshComplete = true;
+  }
+  void OnRemoteOobDataRequest(std::shared_ptr<Device> device, hci::RemoteOobDataRequestView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedRemoteOobDataRequest = true;
+  }
+  void OnUserPasskeyNotification(std::shared_ptr<hci::Device> device, hci::UserPasskeyNotificationView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedUserPasskeyNotification = true;
+  }
+  void OnKeypressNotification(std::shared_ptr<hci::Device> device, hci::KeypressNotificationView packet) {
+    EXPECT_TRUE(packet.IsValid());
+    receivedKeypressNotification = true;
+  }
+};
+
+class SecurityManagerChannelTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    device_ = kDeviceDatabase.CreateClassicDevice(hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}));
+    handler_ = new Handler(&thread_);
+    callback_ = new SecurityManagerChannelCallback();
+    hci_layer_ = new FakeHciLayer();
+    fake_registry_.InjectTestModule(&FakeHciLayer::Factory, hci_layer_);
+    fake_registry_.Start<FakeHciLayer>(&thread_);
+    channel_ = new SecurityManagerChannel(handler_, hci_layer_);
+    channel_->SetChannelListener(callback_);
+  }
+
+  void TearDown() override {
+    channel_->SetChannelListener(nullptr);
+    handler_->Clear();
+    fake_registry_.SynchronizeModuleHandler(&FakeHciLayer::Factory, std::chrono::milliseconds(20));
+    fake_registry_.StopAll();
+    delete handler_;
+    delete channel_;
+    delete callback_;
+  }
+
+  TestModuleRegistry fake_registry_;
+  Thread& thread_ = fake_registry_.GetTestThread();
+  Handler* handler_ = nullptr;
+  FakeHciLayer* hci_layer_ = nullptr;
+  SecurityManagerChannel* channel_ = nullptr;
+  SecurityManagerChannelCallback* callback_ = nullptr;
+  std::shared_ptr<Device> device_ = nullptr;
+};
+
+TEST_F(SecurityManagerChannelTest, setup_teardown) {}
+
+TEST_F(SecurityManagerChannelTest, recv_io_cap_request) {
+  hci_layer_->IncomingEvent(hci::IoCapabilityRequestBuilder::Create(device_->GetAddress()));
+  EXPECT_TRUE(callback_->receivedIoCapabilityRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_io_cap_request_reply) {
+  // Arrange
+  hci::IoCapability io_capability = (hci::IoCapability)0x00;
+  OobDataPresent oob_present = (OobDataPresent)0x00;
+  AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+  auto packet = hci::IoCapabilityRequestReplyBuilder::Create(device_->GetAddress(), io_capability, oob_present,
+                                                             authentication_requirements);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_io_cap_request_neg_reply) {
+  // Arrange
+  auto packet =
+      hci::IoCapabilityRequestNegativeReplyBuilder::Create(device_->GetAddress(), hci::ErrorCode::COMMAND_DISALLOWED);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_io_cap_response) {
+  hci::IoCapability io_capability = (hci::IoCapability)0x00;
+  OobDataPresent oob_present = (OobDataPresent)0x00;
+  AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+  hci_layer_->IncomingEvent(hci::IoCapabilityResponseBuilder::Create(device_->GetAddress(), io_capability, oob_present,
+                                                                     authentication_requirements));
+  EXPECT_TRUE(callback_->receivedIoCapabilityResponse);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_pin_code_request) {
+  hci_layer_->IncomingEvent(hci::PinCodeRequestBuilder::Create(device_->GetAddress()));
+  EXPECT_TRUE(callback_->receivedPinCodeRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_pin_code_request_reply) {
+  // Arrange
+  uint8_t pin_code_length = 6;
+  std::array<uint8_t, 16> pin_code = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+  auto packet = hci::PinCodeRequestReplyBuilder::Create(device_->GetAddress(), pin_code_length, pin_code);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::PIN_CODE_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_pin_code_request_neg_reply) {
+  // Arrange
+  auto packet = hci::PinCodeRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_user_passkey_notification) {
+  uint32_t passkey = 0x00;
+  hci_layer_->IncomingEvent(hci::UserPasskeyNotificationBuilder::Create(device_->GetAddress(), passkey));
+  EXPECT_TRUE(callback_->receivedUserPasskeyNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_reply) {
+  // Arrange
+  auto packet = hci::UserConfirmationRequestReplyBuilder::Create(device_->GetAddress());
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_neg_reply) {
+  // Arrange
+  auto packet = hci::UserConfirmationRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_remote_oob_data_request) {
+  hci_layer_->IncomingEvent(hci::RemoteOobDataRequestBuilder::Create(device_->GetAddress()));
+  EXPECT_TRUE(callback_->receivedRemoteOobDataRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_reply) {
+  // Arrange
+  std::array<uint8_t, 16> c = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+  std::array<uint8_t, 16> r = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+  auto packet = hci::RemoteOobDataRequestReplyBuilder::Create(device_->GetAddress(), c, r);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_neg_reply) {
+  // Arrange
+  auto packet = hci::RemoteOobDataRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_local_oob_data) {
+  // Arrange
+  auto packet = hci::ReadLocalOobDataBuilder::Create();
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::READ_LOCAL_OOB_DATA, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_local_oob_extended_data) {
+  // Arrange
+  auto packet = hci::ReadLocalOobExtendedDataBuilder::Create();
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::READ_LOCAL_OOB_EXTENDED_DATA, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_link_key_request) {
+  hci_layer_->IncomingEvent(hci::LinkKeyRequestBuilder::Create(device_->GetAddress()));
+  EXPECT_TRUE(callback_->receivedLinkKeyRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_link_key_notification) {
+  std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+  hci_layer_->IncomingEvent(
+      hci::LinkKeyNotificationBuilder::Create(device_->GetAddress(), link_key, hci::KeyType::DEBUG_COMBINATION));
+  EXPECT_TRUE(callback_->receivedLinkKeyNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_master_link_key_complete) {
+  uint16_t connection_handle = 0x0;
+  hci_layer_->IncomingEvent(
+      hci::MasterLinkKeyCompleteBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle, hci::KeyFlag::TEMPORARY));
+  EXPECT_TRUE(callback_->receivedMasterLinkKeyComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_change_connection_link_key_complete) {
+  uint16_t connection_handle = 0x0;
+  hci_layer_->IncomingEvent(
+      hci::ChangeConnectionLinkKeyCompleteBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle));
+  EXPECT_TRUE(callback_->receivedChangeConnectionLinkKeyComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_return_link_keys) {
+  std::vector<hci::ZeroKeyAndAddress> keys;
+  hci_layer_->IncomingEvent(hci::ReturnLinkKeysBuilder::Create(keys));
+  EXPECT_TRUE(callback_->receivedReturnLinkKeys);
+}
+
+TEST_F(SecurityManagerChannelTest, send_link_key_request_reply) {
+  // Arrange
+  std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+  auto packet = hci::LinkKeyRequestReplyBuilder::Create(device_->GetAddress(), link_key);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::LINK_KEY_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_link_key_request_neg_reply) {
+  // Arrange
+  auto packet = hci::LinkKeyRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_stored_link_key) {
+  // Arrange
+  auto packet = hci::ReadStoredLinkKeyBuilder::Create(device_->GetAddress(), hci::ReadStoredLinkKeyReadAllFlag::ALL);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::READ_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_write_stored_link_key) {
+  // Arrange
+  std::vector<hci::KeyAndAddress> keys_to_write;
+  auto packet = hci::WriteStoredLinkKeyBuilder::Create(keys_to_write);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::WRITE_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_delete_stored_link_key) {
+  // Arrange
+  auto packet =
+      hci::DeleteStoredLinkKeyBuilder::Create(device_->GetAddress(), hci::DeleteStoredLinkKeyDeleteAllFlag::ALL);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::DELETE_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_encryption_change) {
+  uint16_t connection_handle = 0x0;
+  hci_layer_->IncomingEvent(
+      hci::EncryptionChangeBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle, hci::EncryptionEnabled::ON));
+  EXPECT_TRUE(callback_->receivedEncryptionChange);
+}
+
+TEST_F(SecurityManagerChannelTest, send_refresh_encryption_key) {
+  // Arrange
+  uint16_t connection_handle = 0x0;
+  auto packet = hci::RefreshEncryptionKeyBuilder::Create(connection_handle);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::REFRESH_ENCRYPTION_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_encryption_key_size) {
+  // Arrange
+  uint16_t connection_handle = 0x0;
+  auto packet = hci::ReadEncryptionKeySizeBuilder::Create(connection_handle);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::READ_ENCRYPTION_KEY_SIZE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_simple_pairing_complete) {
+  hci_layer_->IncomingEvent(hci::SimplePairingCompleteBuilder::Create(hci::ErrorCode::SUCCESS, device_->GetAddress()));
+  EXPECT_TRUE(callback_->receivedSimplePairingComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_simple_pairing_mode) {
+  // Arrange
+  auto packet = hci::ReadSimplePairingModeBuilder::Create();
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::READ_SIMPLE_PAIRING_MODE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_write_simple_pairing_mode) {
+  // Arrange
+  auto packet = hci::WriteSimplePairingModeBuilder::Create(hci::Enable::ENABLED);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::WRITE_SIMPLE_PAIRING_MODE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_keypress_notification) {
+  hci_layer_->IncomingEvent(
+      hci::KeypressNotificationBuilder::Create(device_->GetAddress(), hci::KeypressNotificationType::ENTRY_COMPLETED));
+  EXPECT_TRUE(callback_->receivedKeypressNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, send_keypress_notification) {
+  // Arrange
+  auto packet =
+      hci::SendKeypressNotificationBuilder::Create(device_->GetAddress(), hci::KeypressNotificationType::ENTRY_STARTED);
+
+  // Act
+  channel_->SendCommand(device_, std::move(packet));
+  auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+  auto command_packet = GetPacketView(std::move(last_command));
+  hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+  // Assert
+  EXPECT_TRUE(packet_view.IsValid());
+  EXPECT_EQ(OpCode::SEND_KEYPRESS_NOTIFICATION, packet_view.GetOpCode());
+}
+
+}  // namespace
+}  // namespace channel
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/smp/ecc/multipoint_test.cc b/gd/security/ecc/multipoint_test.cc
similarity index 96%
rename from gd/smp/ecc/multipoint_test.cc
rename to gd/security/ecc/multipoint_test.cc
index ebed658..95e43d4 100644
--- a/gd/smp/ecc/multipoint_test.cc
+++ b/gd/security/ecc/multipoint_test.cc
@@ -18,10 +18,10 @@
 
 #include <gtest/gtest.h>
 
-#include "smp/ecc/p_256_ecc_pp.h"
+#include "security/ecc/p_256_ecc_pp.h"
 
 namespace bluetooth {
-namespace smp {
+namespace security {
 namespace ecc {
 
 // Test ECC point validation
@@ -108,5 +108,5 @@
 }
 
 }  // namespace ecc
-}  // namespace smp
+}  // namespace security
 }  // namespace bluetooth
diff --git a/gd/smp/ecc/multprecision.cc b/gd/security/ecc/multprecision.cc
similarity index 98%
rename from gd/smp/ecc/multprecision.cc
rename to gd/security/ecc/multprecision.cc
index 38b6f3f..c2583ed 100644
--- a/gd/smp/ecc/multprecision.cc
+++ b/gd/security/ecc/multprecision.cc
@@ -22,11 +22,11 @@
  *
  ******************************************************************************/
 
-#include "smp/ecc/multprecision.h"
+#include "security/ecc/multprecision.h"
 #include <string.h>
 
 namespace bluetooth {
-namespace smp {
+namespace security {
 namespace ecc {
 
 #define DWORD_BITS 32
@@ -500,5 +500,5 @@
 }
 
 }  // namespace ecc
-}  // namespace smp
+}  // namespace security
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/multprecision.h b/gd/security/ecc/multprecision.h
similarity index 97%
rename from gd/smp/ecc/multprecision.h
rename to gd/security/ecc/multprecision.h
index 01bb9ad..ad149cd 100644
--- a/gd/smp/ecc/multprecision.h
+++ b/gd/security/ecc/multprecision.h
@@ -26,7 +26,7 @@
 #include <cstdint>
 
 namespace bluetooth {
-namespace smp {
+namespace security {
 namespace ecc {
 
 #define KEY_LENGTH_DWORDS_P256 8
@@ -52,5 +52,5 @@
 void multiprecision_fast_mod_P256(uint32_t* c, const uint32_t* a, const uint32_t* modp);
 
 }  // namespace ecc
-}  // namespace smp
+}  // namespace security
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/p_256_ecc_pp.cc b/gd/security/ecc/p_256_ecc_pp.cc
similarity index 98%
rename from gd/smp/ecc/p_256_ecc_pp.cc
rename to gd/security/ecc/p_256_ecc_pp.cc
index e5d76c8..ecb805c 100644
--- a/gd/smp/ecc/p_256_ecc_pp.cc
+++ b/gd/security/ecc/p_256_ecc_pp.cc
@@ -22,14 +22,14 @@
  *  Cryptography for private public key
  *
  ******************************************************************************/
-#include "smp/ecc/p_256_ecc_pp.h"
+#include "security/ecc/p_256_ecc_pp.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include "smp/ecc/multprecision.h"
+#include "security/ecc/multprecision.h"
 
 namespace bluetooth {
-namespace smp {
+namespace security {
 namespace ecc {
 
 const uint32_t* modp = curve_p256.p;
@@ -260,5 +260,5 @@
 }
 
 }  // namespace ecc
-}  // namespace smp
+}  // namespace security
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/smp/ecc/p_256_ecc_pp.h b/gd/security/ecc/p_256_ecc_pp.h
similarity index 96%
rename from gd/smp/ecc/p_256_ecc_pp.h
rename to gd/security/ecc/p_256_ecc_pp.h
index 4fc4653..93af7ee 100644
--- a/gd/smp/ecc/p_256_ecc_pp.h
+++ b/gd/security/ecc/p_256_ecc_pp.h
@@ -25,10 +25,10 @@
 
 #pragma once
 
-#include "smp/ecc/multprecision.h"
+#include "security/ecc/multprecision.h"
 
 namespace bluetooth {
-namespace smp {
+namespace security {
 namespace ecc {
 
 struct Point {
@@ -54,10 +54,10 @@
 
 // P-256 elliptic curve, as per BT Spec 5.1 Vol 2, Part H 7.6
 static constexpr elliptic_curve_t curve_p256{
-    .p = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x00000001, 0xFFFFFFFF},
-    .omega = {0},
     .a = {0},
     .b = {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8},
+    .p = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x00000001, 0xFFFFFFFF},
+    .omega = {0},
 
     .G = {.x = {0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2},
           .y = {0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2}},
@@ -71,5 +71,5 @@
 #define ECC_PointMult(q, p, n) ECC_PointMult_Bin_NAF(q, p, n)
 
 }  // namespace ecc
-}  // namespace smp
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/ecdh_keys.cc b/gd/security/ecdh_keys.cc
new file mode 100644
index 0000000..fa3d794
--- /dev/null
+++ b/gd/security/ecdh_keys.cc
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ *  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 "security/ecdh_keys.h"
+
+/**********************************************************************************************************************
+ TODO: We should have random number management in separate file, and we
+       should honour all the random number requirements from the spec!!
+**********************************************************************************************************************/
+#include <chrono>
+#include <cstdlib>
+
+#include "security/ecc/p_256_ecc_pp.h"
+
+namespace {
+template <size_t SIZE>
+static std::array<uint8_t, SIZE> GenerateRandom() {
+  // TODO:  We need a proper  random number generator here.
+  // use current time as seed for random generator
+  std::srand(std::time(nullptr));
+  std::array<uint8_t, SIZE> r;
+  for (size_t i = 0; i < SIZE; i++) r[i] = std::rand();
+  return r;
+}
+}  // namespace
+/*********************************************************************************************************************/
+
+namespace bluetooth {
+namespace security {
+
+std::pair<std::array<uint8_t, 32>, EcdhPublicKey> GenerateECDHKeyPair() {
+  std::array<uint8_t, 32> private_key = GenerateRandom<32>();
+  ecc::Point public_key;
+
+  ECC_PointMult(&public_key, &(ecc::curve_p256.G), (uint32_t*)private_key.data());
+
+  EcdhPublicKey pk;
+  memcpy(pk.x.data(), public_key.x, 32);
+  memcpy(pk.y.data(), public_key.y, 32);
+
+  /* private_key, public key pair */
+  return std::make_pair<std::array<uint8_t, 32>, EcdhPublicKey>(std::move(private_key), std::move(pk));
+}
+
+bool ValidateECDHPoint(EcdhPublicKey pk) {
+  ecc::Point public_key;
+  memcpy(public_key.x, pk.x.data(), 32);
+  memcpy(public_key.y, pk.y.data(), 32);
+  memset(public_key.z, 0, 32);
+  return ECC_ValidatePoint(public_key);
+}
+
+std::array<uint8_t, 32> ComputeDHKey(std::array<uint8_t, 32> my_private_key, EcdhPublicKey remote_public_key) {
+  ecc::Point peer_publ_key, new_publ_key;
+  uint32_t private_key[8];
+  memcpy(private_key, my_private_key.data(), 32);
+  memcpy(peer_publ_key.x, remote_public_key.x.data(), 32);
+  memcpy(peer_publ_key.y, remote_public_key.y.data(), 32);
+  ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key);
+
+  std::array<uint8_t, 32> dhkey;
+  memcpy(dhkey.data(), new_publ_key.x, 32);
+  return dhkey;
+}
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/ecdh_keys.h b/gd/security/ecdh_keys.h
new file mode 100644
index 0000000..8ec25a8
--- /dev/null
+++ b/gd/security/ecdh_keys.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ *  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 <array>
+
+namespace bluetooth {
+namespace security {
+
+struct EcdhPublicKey {
+  std::array<uint8_t, 32> x;
+  std::array<uint8_t, 32> y;
+};
+
+/* this generates private and public Eliptic Curve Diffie Helman keys */
+std::pair<std::array<uint8_t, 32>, EcdhPublicKey> GenerateECDHKeyPair();
+
+/* This function validates that the given public key (point) lays on the special
+ * Bluetooth curve */
+bool ValidateECDHPoint(EcdhPublicKey pk);
+
+std::array<uint8_t, 32> ComputeDHKey(std::array<uint8_t, 32> my_private_key, EcdhPublicKey remote_public_key);
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/initial_informations.h b/gd/security/initial_informations.h
new file mode 100644
index 0000000..db560bd
--- /dev/null
+++ b/gd/security/initial_informations.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ *  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 <optional>
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+#include "hci/address_with_type.h"
+#include "hci/le_security_interface.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+#include "security/pairing_failure.h"
+#include "security/smp_packets.h"
+#include "security/ui.h"
+
+namespace bluetooth {
+namespace security {
+
+using DistributedKeys =
+    std::tuple<std::optional<crypto_toolbox::Octet16> /* ltk */, std::optional<uint16_t> /*ediv*/,
+               std::optional<std::array<uint8_t, 8>> /* rand */, std::optional<Address> /* Identity address */,
+               AddrType, std::optional<crypto_toolbox::Octet16> /* IRK */,
+               std::optional<crypto_toolbox::Octet16>> /* Signature Key */;
+
+/* This class represents the result of pairing, as returned from Pairing Handler */
+struct PairingResult {
+  hci::AddressWithType connection_address;
+  DistributedKeys distributed_keys;
+};
+
+using PairingResultOrFailure = std::variant<PairingResult, PairingFailure>;
+
+/* Data we use for Out Of Band Pairing */
+struct MyOobData {
+  /*  private key is just for this single pairing only, so it might be safe to
+   * expose it to other parts of stack. It should not be exposed to upper
+   * layers though */
+  std::array<uint8_t, 32> private_key;
+  EcdhPublicKey public_key;
+  crypto_toolbox::Octet16 c;
+  crypto_toolbox::Octet16 r;
+};
+
+/* This structure is filled and send to PairingHandlerLe to initiate the Pairing process with remote device */
+struct InitialInformations {
+  hci::Role my_role;
+  hci::AddressWithType my_connection_address;
+
+  /* My capabilities, as in pairing request/response */
+  struct {
+    IoCapability io_capability;
+    OobDataFlag oob_data_flag;
+    uint8_t auth_req;
+    uint8_t maximum_encryption_key_size;
+    uint8_t initiator_key_distribution;
+    uint8_t responder_key_distribution;
+  } myPairingCapabilities;
+
+  /* was it remote device that initiated the Pairing ? */
+  bool remotely_initiated;
+  uint16_t connection_handle;
+  hci::AddressWithType remote_connection_address;
+  std::string remote_name;
+
+  /* contains pairing request, if the pairing was remotely initiated */
+  std::optional<PairingRequestView> pairing_request;
+
+  struct out_of_band_data {
+    crypto_toolbox::Octet16 le_sc_c; /* LE Secure Connections Confirmation Value */
+    crypto_toolbox::Octet16 le_sc_r; /* LE Secure Connections Random Value */
+
+    crypto_toolbox::Octet16 security_manager_tk_value; /* OOB data for LE Legacy Pairing */
+  };
+
+  // If we received OOB data from remote device, this field contains it.
+  std::optional<out_of_band_data> remote_oob_data;
+  std::optional<MyOobData> my_oob_data;
+
+  /* Used by Pairing Handler to present user with requests*/
+  UI* ui_handler;
+
+  /* HCI interface to use */
+  hci::LeSecurityInterface* le_security_interface;
+
+  os::EnqueueBuffer<packet::BasePacketBuilder>* proper_l2cap_interface;
+  os::Handler* l2cap_handler;
+
+  /* Callback to execute once the Pairing process is finished */
+  std::function<void(PairingResultOrFailure)> OnPairingFinished;
+};
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/internal/security_manager_impl.cc b/gd/security/internal/security_manager_impl.cc
new file mode 100644
index 0000000..26179b5
--- /dev/null
+++ b/gd/security/internal/security_manager_impl.cc
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ *  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 "security_manager_impl.h"
+
+#include <iostream>
+#include <unordered_map>
+
+#include "os/log.h"
+#include "security/pairing/classic_pairing_handler.h"
+#include "security/security_manager.h"
+
+using namespace bluetooth::security::internal;
+using bluetooth::hci::Device;
+using bluetooth::hci::DeviceType;
+using bluetooth::security::ISecurityManagerListener;
+using bluetooth::security::pairing::PairingHandler;
+
+namespace {
+std::unordered_map<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>> pairing_handler_map_;
+
+void dispatch_new_pairing_handler(std::shared_ptr<bluetooth::security::record::SecurityRecord> record) {
+  auto entry = pairing_handler_map_.find(record->GetDevice());
+  if (entry != pairing_handler_map_.end()) {
+    LOG_WARN("Device already has a pairing handler, and is in the middle of pairing!");
+    return;
+  }
+  std::unique_ptr<PairingHandler> pairing_handler = nullptr;
+  switch (record->GetDevice()->GetDeviceType()) {
+    case DeviceType::CLASSIC:
+      pairing_handler = std::make_unique<bluetooth::security::pairing::ClassicPairingHandler>(record);
+      break;
+    default:
+      ASSERT_LOG(false, "Pairing type %d not implemented!", record->GetDevice()->GetDeviceType());
+  }
+  auto new_entry = std::pair<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>>(record->GetDevice(),
+                                                                                       std::move(pairing_handler));
+  pairing_handler_map_.insert(std::move(new_entry));
+}
+}  // namespace
+
+void SecurityManagerImpl::Init() {
+  // TODO(optedoblivion): Populate security record memory map from disk
+  //  security_manager_channel_->SetChannelListener(this);
+}
+
+void SecurityManagerImpl::CreateBond(std::shared_ptr<hci::ClassicDevice> device) {
+  std::string uuid = device->GetUuid();
+  // Security record check
+  //  if (device_database_->GetDeviceById(uuid) != nullptr) {
+  //    LOG_WARN("Device already exists in the database");
+  // TODO(optedoblivion): Check security record if device is already bonded
+  // if no security record, need to initiate bonding
+  // if security record and not bonded, need to initiate bonding
+  // if security record and is bonded, then do nothing
+  //  }
+
+  // device_database_->AddDevice(device);
+  // Create security record
+  // Pass to pairing handler
+  std::shared_ptr<record::SecurityRecord> record = std::make_shared<record::SecurityRecord>(device);
+  dispatch_new_pairing_handler(record);
+  // init the pairing handler
+  // Update bonded flag on security record
+  // Update bonded flag on device to BONDING (pairing handler does this)
+}
+
+void SecurityManagerImpl::CancelBond(std::shared_ptr<hci::ClassicDevice> device) {
+  auto entry = pairing_handler_map_.find(device);
+  if (entry != pairing_handler_map_.end()) {
+    pairing_handler_map_.erase(device);
+  }
+  // Remove from DB
+  // device_database_->RemoveDevice(device);
+  // Remove from map, no longer will the event queue use it
+  // If currently bonding, cancel pairing handler job
+  // else, cancel fails
+}
+
+void SecurityManagerImpl::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) {
+  CancelBond(device);
+  // Update bonded flag on device to UNBONDED
+  // Signal disconnect
+  // Signal unbonding
+  // Remove security record
+  // Signal Remove from database
+}
+
+void SecurityManagerImpl::RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler) {
+  for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
+    if (it->first == listener) {
+      LOG_ALWAYS_FATAL("Listener has already been registered!");
+    }
+  }
+
+  listeners_.push_back({listener, handler});
+}
+
+void SecurityManagerImpl::UnregisterCallbackListener(ISecurityManagerListener* listener) {
+  for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
+    if (it->first == listener) {
+      listeners_.erase(it);
+      return;
+    }
+  }
+
+  LOG_ALWAYS_FATAL("Listener has not been registered!");
+}
+
+void SecurityManagerImpl::NotifyDeviceBonded(std::shared_ptr<Device> device) {
+  for (auto& iter : listeners_) {
+    iter.second->Post(common::Bind(&ISecurityManagerListener::OnDeviceBonded, common::Unretained(iter.first), device));
+  }
+}
+
+void SecurityManagerImpl::NotifyDeviceBondFailed(std::shared_ptr<Device> device) {
+  for (auto& iter : listeners_) {
+    iter.second->Post(
+        common::Bind(&ISecurityManagerListener::OnDeviceBondFailed, common::Unretained(iter.first), device));
+  }
+}
+
+void SecurityManagerImpl::NotifyDeviceUnbonded(std::shared_ptr<Device> device) {
+  for (auto& iter : listeners_) {
+    iter.second->Post(
+        common::Bind(&ISecurityManagerListener::OnDeviceUnbonded, common::Unretained(iter.first), device));
+  }
+}
diff --git a/gd/security/internal/security_manager_impl.h b/gd/security/internal/security_manager_impl.h
new file mode 100644
index 0000000..23b39e1
--- /dev/null
+++ b/gd/security/internal/security_manager_impl.h
@@ -0,0 +1,124 @@
+/*
+ * 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 "hci/classic_device.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "os/handler.h"
+#include "security/channel/security_manager_channel.h"
+
+#include <utility>
+
+namespace bluetooth {
+namespace security {
+
+class ISecurityManagerListener;
+
+namespace internal {
+
+class SecurityManagerImpl /*: public channel::ISecurityManagerChannelListener*/ {
+ public:
+  explicit SecurityManagerImpl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module,
+                               l2cap::classic::L2capClassicModule* l2cap_classic_module,
+                               channel::SecurityManagerChannel* security_manager_channel)
+      : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module),
+        l2cap_classic_module_(l2cap_classic_module), security_manager_channel_(security_manager_channel) {}
+  virtual ~SecurityManagerImpl() = default;
+
+  // All APIs must be invoked in SM layer handler
+
+  /**
+   * Initialize the security record map from an internal device database.
+   */
+  void Init();
+
+  /**
+   * Checks the device for existing bond, if not bonded, initiates pairing.
+   *
+   * @param device pointer to device we want to bond with
+   * @return true if bonded or pairing started successfully, false if currently pairing
+   */
+  void CreateBond(std::shared_ptr<hci::ClassicDevice> device);
+
+  /* void CreateBond(std::shared_ptr<hci::LeDevice> device); */
+
+  /**
+   * Cancels the pairing process for this device.
+   *
+   * @param device pointer to device with which we want to cancel our bond
+   * @return <code>true</code> if successfully stopped
+   */
+  void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+  /* void CancelBond(std::shared_ptr<hci::LeDevice> device); */
+
+  /**
+   * Disassociates the device and removes the persistent LTK
+   *
+   * @param device pointer to device we want to forget
+   * @return true if removed
+   */
+  void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+  /* void RemoveBond(std::shared_ptr<hci::LeDevice> device); */
+
+  /**
+   * Register to listen for callback events from SecurityManager
+   *
+   * @param listener ISecurityManagerListener instance to handle callbacks
+   */
+  void RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler);
+
+  /**
+   * Unregister listener for callback events from SecurityManager
+   *
+   * @param listener ISecurityManagerListener instance to unregister
+   */
+  void UnregisterCallbackListener(ISecurityManagerListener* listener);
+
+ protected:
+  std::vector<std::pair<ISecurityManagerListener*, os::Handler*>> listeners_;
+  void NotifyDeviceBonded(std::shared_ptr<bluetooth::hci::Device> device);
+  void NotifyDeviceBondFailed(std::shared_ptr<bluetooth::hci::Device> device);
+  void NotifyDeviceUnbonded(std::shared_ptr<bluetooth::hci::Device> device);
+
+  // ISecurityManagerChannel
+  void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+                                         hci::ChangeConnectionLinkKeyCompleteView packet);
+  void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet);
+  void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet);
+  void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet);
+  void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet);
+  void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet);
+  void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet);
+  void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet);
+  void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet);
+  void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet);
+  void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device,
+                                      hci::EncryptionKeyRefreshCompleteView packet);
+  void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet);
+
+ private:
+  os::Handler* security_handler_ __attribute__((unused));
+  l2cap::le::L2capLeModule* l2cap_le_module_ __attribute__((unused));
+  l2cap::classic::L2capClassicModule* l2cap_classic_module_ __attribute__((unused));
+  channel::SecurityManagerChannel* security_manager_channel_ __attribute__((unused));
+};
+}  // namespace internal
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/pairing/classic_pairing_handler.h b/gd/security/pairing/classic_pairing_handler.h
new file mode 100644
index 0000000..fc8eed4
--- /dev/null
+++ b/gd/security/pairing/classic_pairing_handler.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  Copyright 2019 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License") override;
+ *  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 "pairing_handler.h"
+
+#include "security/smp_packets.h"
+
+using namespace bluetooth::security::pairing;
+
+namespace bluetooth {
+namespace security {
+namespace pairing {
+
+class ClassicPairingHandler : public PairingHandler {
+ public:
+  explicit ClassicPairingHandler(std::shared_ptr<record::SecurityRecord> record) : PairingHandler(record) {}
+
+  void Init() {
+    // Set auth required
+    // Connect to device
+  }
+};
+
+}  // namespace pairing
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/pairing/pairing_handler.h b/gd/security/pairing/pairing_handler.h
new file mode 100644
index 0000000..61cad62
--- /dev/null
+++ b/gd/security/pairing/pairing_handler.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ *  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 <memory>
+#include <vector>
+
+#include "hci/device.h"
+#include "security/channel/security_manager_channel.h"
+#include "security/record/security_record.h"
+#include "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+namespace pairing {
+
+/**
+ * Base structure for handling pairing events.
+ *
+ * <p>Extend this class in order to implement a new style of pairing.
+ */
+class PairingHandler {
+ public:
+  PairingHandler(std::shared_ptr<record::SecurityRecord> record) : record_(record){};
+  virtual ~PairingHandler() = default;
+
+  std::shared_ptr<record::SecurityRecord> GetRecord() {
+    return record_;
+  }
+
+ private:
+  std::shared_ptr<record::SecurityRecord> record_ __attribute__((unused));
+};
+
+}  // namespace pairing
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/pairing_failure.h b/gd/security/pairing_failure.h
new file mode 100644
index 0000000..f7bbbae
--- /dev/null
+++ b/gd/security/pairing_failure.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ *  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 "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+
+/* This structure holds the information about the failure in case of airing failure */
+struct PairingFailure {
+  /* A place in code that triggered this failure. It can be modified by functions that pass the error to a location that
+   * better reflect the current state of flow. i.e. instead of generic location responsible for waiting for packet,
+   * replace it with location of receiving specific packet in a specific flow */
+  // base::Location location;
+
+  /* This is the failure message, that will be passed, either into upper layers,
+   * or to the metrics in future */
+  std::string message;
+
+  /* If failure is due to mismatch of received code, this contains the received opcode */
+  Code received_code_;
+
+  /* if the failure is due to "SMP failure", this field contains the reson code
+   */
+  PairingFailedReason reason;
+
+  PairingFailure(/*const base::Location& location, */ const std::string& message)
+      : /*location(location), */ message(message) {}
+
+  PairingFailure(/*const base::Location& location, */ const std::string& message, Code received_code)
+      : /*location(location), */ message(message), received_code_(received_code) {}
+
+  PairingFailure(/*const base::Location& location, */ const std::string& message, PairingFailedReason reason)
+      : /*location(location),*/ message(message), reason(reason) {}
+};
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le.cc b/gd/security/pairing_handler_le.cc
new file mode 100644
index 0000000..0484971
--- /dev/null
+++ b/gd/security/pairing_handler_le.cc
@@ -0,0 +1,391 @@
+/******************************************************************************
+ *
+ *  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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+void PairingHandlerLe::PairingMain(InitialInformations i) {
+  LOG_INFO("Pairing Started");
+
+  if (i.remotely_initiated) {
+    LOG_INFO("Was remotely initiated, presenting user with the accept prompt");
+    i.ui_handler->DisplayPairingPrompt(i.remote_connection_address, i.remote_name);
+
+    // If pairing was initiated by remote device, wait for the user to accept
+    // the request from the UI.
+    LOG_INFO("Waiting for the prompt response");
+    std::optional<PairingEvent> pairingAccepted = WaitUiPairingAccept();
+    if (!pairingAccepted || pairingAccepted->ui_value == 0) {
+      LOG_INFO("User either did not accept the remote pairing, or the prompt timed out");
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+      i.OnPairingFinished(PairingFailure("User either did not accept the remote pairing, or the prompt timed out"));
+      return;
+    }
+
+    LOG_INFO("Pairing prompt accepted");
+  }
+
+  /************************************************ PHASE 1 *********************************************************/
+  Phase1ResultOrFailure phase_1_result = ExchangePairingFeature(i);
+  if (std::holds_alternative<PairingFailure>(phase_1_result)) {
+    LOG_WARN("Pairing failed in phase 1");
+    // We already send pairing fialed in lower layer. Which one should do that ? how about disconneciton?
+    // SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+    // TODO: disconnect?
+    i.OnPairingFinished(std::get<PairingFailure>(phase_1_result));
+    return;
+  }
+
+  auto [pairing_request, pairing_response] = std::get<Phase1Result>(phase_1_result);
+
+  /************************************************ PHASE 2 *********************************************************/
+  if (pairing_request.GetAuthReq() & pairing_response.GetAuthReq() & AuthReqMaskSc) {
+    // 2.3.5.6 LE Secure Connections pairing phase 2
+    LOG_INFO("Pairing Phase 2 LE Secure connections Started");
+
+    /*
+    TODO: what to do with this piece of spec ?
+    If Secure Connections pairing has been initiated over BR/EDR, the
+    following fields of the SM Pairing Request PDU are reserved for future use:
+     • the IO Capability field,
+     • the OOB data flag field, and
+     • all bits in the Auth Req field except the CT2 bit.
+    */
+
+    OobDataFlag remote_have_oob_data =
+        IAmMaster(i) ? pairing_response.GetOobDataFlag() : pairing_request.GetOobDataFlag();
+
+    auto key_exchange_result = ExchangePublicKeys(i, remote_have_oob_data);
+    if (std::holds_alternative<PairingFailure>(key_exchange_result)) {
+      LOG_ERROR("Public key exchange failed");
+      i.OnPairingFinished(std::get<PairingFailure>(key_exchange_result));
+      return;
+    }
+    auto [PKa, PKb, dhkey] = std::get<KeyExchangeResult>(key_exchange_result);
+
+    // Public key exchange finished, Diffie-Hellman key computed.
+
+    Stage1ResultOrFailure stage1result = DoSecureConnectionsStage1(i, PKa, PKb, pairing_request, pairing_response);
+    if (std::holds_alternative<PairingFailure>(stage1result)) {
+      i.OnPairingFinished(std::get<PairingFailure>(stage1result));
+      return;
+    }
+
+    Stage2ResultOrFailure stage_2_result = DoSecureConnectionsStage2(i, PKa, PKb, pairing_request, pairing_response,
+                                                                     std::get<Stage1Result>(stage1result), dhkey);
+    if (std::holds_alternative<PairingFailure>(stage_2_result)) {
+      i.OnPairingFinished(std::get<PairingFailure>(stage_2_result));
+      return;
+    }
+
+    Octet16 ltk = std::get<Octet16>(stage_2_result);
+    if (IAmMaster(i)) {
+      SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, ltk);
+    }
+
+  } else {
+    // 2.3.5.5 LE legacy pairing phase 2
+    LOG_INFO("Pairing Phase 2 LE legacy pairing Started");
+
+    LegacyStage1ResultOrFailure stage1result = DoLegacyStage1(i, pairing_request, pairing_response);
+    if (std::holds_alternative<PairingFailure>(stage1result)) {
+      LOG_ERROR("Phase 1 failed");
+      i.OnPairingFinished(std::get<PairingFailure>(stage1result));
+      return;
+    }
+
+    Octet16 tk = std::get<Octet16>(stage1result);
+    StkOrFailure stage2result = DoLegacyStage2(i, pairing_request, pairing_response, tk);
+    if (std::holds_alternative<PairingFailure>(stage2result)) {
+      LOG_ERROR("stage 2 failed");
+      i.OnPairingFinished(std::get<PairingFailure>(stage2result));
+      return;
+    }
+
+    Octet16 stk = std::get<Octet16>(stage2result);
+    if (IAmMaster(i)) {
+      SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, stk);
+    }
+  }
+
+  /************************************************ PHASE 3 *********************************************************/
+  auto encryption_change_result = WaitEncryptionChanged();
+  if (std::holds_alternative<PairingFailure>(encryption_change_result)) {
+    LOG_ERROR("encryption change failed");
+    i.OnPairingFinished(std::get<PairingFailure>(encryption_change_result));
+    return;
+  } else if (std::holds_alternative<EncryptionChangeView>(encryption_change_result)) {
+    EncryptionChangeView encryption_changed = std::get<EncryptionChangeView>(encryption_change_result);
+    if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS ||
+        encryption_changed.GetEncryptionEnabled() != hci::EncryptionEnabled::ON) {
+      i.OnPairingFinished(PairingFailure("Encryption change failed"));
+    }
+  } else if (std::holds_alternative<EncryptionKeyRefreshCompleteView>(encryption_change_result)) {
+    EncryptionKeyRefreshCompleteView encryption_changed =
+        std::get<EncryptionKeyRefreshCompleteView>(encryption_change_result);
+    if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS) {
+      i.OnPairingFinished(PairingFailure("Encryption key refresh failed"));
+    }
+  } else {
+    i.OnPairingFinished(PairingFailure("Unknown case of encryption change result"));
+  }
+
+  DistributedKeysOrFailure keyExchangeStatus = DistributeKeys(i, pairing_response);
+  if (std::holds_alternative<PairingFailure>(keyExchangeStatus)) {
+    i.OnPairingFinished(std::get<PairingFailure>(keyExchangeStatus));
+    LOG_ERROR("Key exchange failed");
+    return;
+  }
+
+  i.OnPairingFinished(PairingResult{
+      .connection_address = i.remote_connection_address,
+      .distributed_keys = std::get<DistributedKeys>(keyExchangeStatus),
+  });
+}
+
+Phase1ResultOrFailure PairingHandlerLe::ExchangePairingFeature(const InitialInformations& i) {
+  LOG_INFO("Phase 1 start");
+
+  if (IAmMaster(i)) {
+    // Send Pairing Request
+    const auto& x = i.myPairingCapabilities;
+    auto pairing_request_builder =
+        PairingRequestBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size,
+                                      x.initiator_key_distribution, x.responder_key_distribution);
+    // basically pairing_request = myPairingCapabilities;
+
+    // Convert builder to view
+    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+    BitInserter it(*packet_bytes);
+    pairing_request_builder->Serialize(it);
+    PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+    auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+    auto pairing_request = PairingRequestView::Create(temp_cmd_view);
+    ASSERT(pairing_request.IsValid());
+
+    LOG_INFO("Sending Pairing Request");
+    SendL2capPacket(i, std::move(pairing_request_builder));
+
+    LOG_INFO("Waiting for Pairing Response");
+    auto response = WaitPairingResponse();
+
+    /* There is a potential collision where the slave initiates the pairing at the same time we initiate it, by sending
+     * security request. */
+    if (std::holds_alternative<PairingFailure>(response) &&
+        std::get<PairingFailure>(response).received_code_ == Code::SECURITY_REQUEST) {
+      LOG_INFO("Received security request, waiting for Pairing Response again...");
+      response = WaitPairingResponse();
+    }
+
+    if (std::holds_alternative<PairingFailure>(response)) {
+      // TODO: should the failure reason be different in some cases ? How about
+      // when we lost connection ? Don't send anything at all, or have L2CAP
+      // layer ignore it?
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+      return std::get<PairingFailure>(response);
+    }
+
+    auto pairing_response = std::get<PairingResponseView>(response);
+
+    LOG_INFO("Phase 1 finish");
+    return Phase1Result{pairing_request, pairing_response};
+  } else {
+    std::optional<PairingRequestView> pairing_request;
+
+    if (i.remotely_initiated) {
+      if (!i.pairing_request.has_value()) {
+        return PairingFailure("You must pass PairingRequest as a initial information to slave!");
+      }
+
+      pairing_request = i.pairing_request.value();
+
+      if (!pairing_request->IsValid()) return PairingFailure("Malformed PairingRequest");
+    } else {
+      SendL2capPacket(i, SecurityRequestBuilder::Create(i.myPairingCapabilities.auth_req));
+
+      LOG_INFO("Waiting for Pairing Request");
+      auto request = WaitPairingRequest();
+      if (std::holds_alternative<PairingFailure>(request)) {
+        LOG_INFO("%s", std::get<PairingFailure>(request).message.c_str());
+        SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+        return std::get<PairingFailure>(request);
+      }
+
+      pairing_request = std::get<PairingRequestView>(request);
+    }
+
+    // Send Pairing Request
+    const auto& x = i.myPairingCapabilities;
+    // basically pairing_response_builder = my_first_packet;
+    // We are not allowed to enable bits that the remote did not allow us to set in initiator_key_dist and
+    // responder_key_distribution
+    auto pairing_response_builder =
+        PairingResponseBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size,
+                                       x.initiator_key_distribution & pairing_request->GetInitiatorKeyDistribution(),
+                                       x.responder_key_distribution & pairing_request->GetResponderKeyDistribution());
+
+    // Convert builder to view
+    std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+    BitInserter it(*packet_bytes);
+    pairing_response_builder->Serialize(it);
+    PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+    auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+    auto pairing_response = PairingResponseView::Create(temp_cmd_view);
+    ASSERT(pairing_response.IsValid());
+
+    LOG_INFO("Sending Pairing Response");
+    SendL2capPacket(i, std::move(pairing_response_builder));
+
+    LOG_INFO("Phase 1 finish");
+    return Phase1Result{pairing_request.value(), pairing_response};
+  }
+}
+
+DistributedKeysOrFailure PairingHandlerLe::DistributeKeys(const InitialInformations& i,
+                                                          const PairingResponseView& pairing_response) {
+  LOG_INFO("Key distribution start");
+
+  const uint8_t& keys_i_receive =
+      IAmMaster(i) ? pairing_response.GetResponderKeyDistribution() : pairing_response.GetInitiatorKeyDistribution();
+  const uint8_t& keys_i_send =
+      IAmMaster(i) ? pairing_response.GetInitiatorKeyDistribution() : pairing_response.GetResponderKeyDistribution();
+
+  // TODO: obtain actual values!
+
+  Octet16 my_ltk = {0};
+  uint16_t my_ediv{0};
+  std::array<uint8_t, 8> my_rand = {0};
+
+  Octet16 my_irk = {0x01};
+  Address my_identity_address;
+  AddrType my_identity_address_type = AddrType::PUBLIC;
+  Octet16 my_signature_key{0};
+
+  if (IAmMaster(i)) {
+    // EncKey is unused for LE Secure Connections
+    DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive);
+    if (std::holds_alternative<PairingFailure>(keys)) {
+      return keys;
+    }
+
+    SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type,
+             my_signature_key);
+    LOG_INFO("Key distribution finish");
+    return keys;
+  } else {
+    SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type,
+             my_signature_key);
+
+    DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive);
+    if (std::holds_alternative<PairingFailure>(keys)) {
+      return keys;
+    }
+    LOG_INFO("Key distribution finish");
+    return keys;
+  }
+}
+
+DistributedKeysOrFailure PairingHandlerLe::ReceiveKeys(const uint8_t& keys_i_receive) {
+  std::optional<Octet16> ltk;                 /* Legacy only */
+  std::optional<uint16_t> ediv;               /* Legacy only */
+  std::optional<std::array<uint8_t, 8>> rand; /* Legacy only */
+  std::optional<Address> identity_address;
+  AddrType identity_address_type;
+  std::optional<Octet16> irk;
+  std::optional<Octet16> signature_key;
+
+  if (keys_i_receive & KeyMaskEnc) {
+    {
+      auto packet = WaitEncryptionInformation();
+      if (std::holds_alternative<PairingFailure>(packet)) {
+        LOG_ERROR(" Was expecting Encryption Information but did not receive!");
+        return std::get<PairingFailure>(packet);
+      }
+      ltk = std::get<EncryptionInformationView>(packet).GetLongTermKey();
+    }
+
+    {
+      auto packet = WaitMasterIdentification();
+      if (std::holds_alternative<PairingFailure>(packet)) {
+        LOG_ERROR(" Was expecting Master Identification but did not receive!");
+        return std::get<PairingFailure>(packet);
+      }
+      ediv = std::get<MasterIdentificationView>(packet).GetEdiv();
+      rand = std::get<MasterIdentificationView>(packet).GetRand();
+    }
+  }
+
+  if (keys_i_receive & KeyMaskId) {
+    auto packet = WaitIdentityInformation();
+    if (std::holds_alternative<PairingFailure>(packet)) {
+      LOG_ERROR(" Was expecting Identity Information but did not receive!");
+      return std::get<PairingFailure>(packet);
+    }
+
+    LOG_INFO("Received Identity Information");
+    irk = std::get<IdentityInformationView>(packet).GetIdentityResolvingKey();
+
+    auto iapacket = WaitIdentityAddressInformation();
+    if (std::holds_alternative<PairingFailure>(iapacket)) {
+      LOG_ERROR(
+          "Was expecting Identity Address Information but did "
+          "not receive!");
+      return std::get<PairingFailure>(iapacket);
+    }
+    LOG_INFO("Received Identity Address Information");
+    identity_address = std::get<IdentityAddressInformationView>(iapacket).GetBdAddr();
+    identity_address_type = std::get<IdentityAddressInformationView>(iapacket).GetAddrType();
+  }
+
+  if (keys_i_receive & KeyMaskSign) {
+    auto packet = WaitSigningInformation();
+    if (std::holds_alternative<PairingFailure>(packet)) {
+      LOG_ERROR(" Was expecting Signing Information but did not receive!");
+      return std::get<PairingFailure>(packet);
+    }
+
+    LOG_INFO("Received Signing Information");
+    signature_key = std::get<SigningInformationView>(packet).GetSignatureKey();
+  }
+
+  return DistributedKeys{ltk, ediv, rand, identity_address, identity_address_type, irk, signature_key};
+}
+
+void PairingHandlerLe::SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv,
+                                std::array<uint8_t, 8> rand, Octet16 irk, Address identity_address,
+                                AddrType identity_addres_type, Octet16 signature_key) {
+  if (keys_i_send & KeyMaskEnc) {
+    SendL2capPacket(i, EncryptionInformationBuilder::Create(ltk));
+    SendL2capPacket(i, MasterIdentificationBuilder::Create(ediv, rand));
+  }
+
+  if (keys_i_send & KeyMaskId) {
+    SendL2capPacket(i, IdentityInformationBuilder::Create(irk));
+
+    SendL2capPacket(i, IdentityAddressInformationBuilder::Create(identity_addres_type, identity_address));
+  }
+
+  if (keys_i_send & KeyMaskSign) {
+    SendL2capPacket(i, SigningInformationBuilder::Create(signature_key));
+  }
+}
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le.h b/gd/security/pairing_handler_le.h
new file mode 100644
index 0000000..4c7fc0c
--- /dev/null
+++ b/gd/security/pairing_handler_le.h
@@ -0,0 +1,493 @@
+/******************************************************************************
+ *
+ *  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 <array>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <variant>
+
+#include "common/bind.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+#include "hci/hci_packets.h"
+#include "hci/le_security_interface.h"
+#include "packet/packet_view.h"
+#include "security/ecdh_keys.h"
+#include "security/initial_informations.h"
+#include "security/pairing_failure.h"
+#include "security/smp_packets.h"
+#include "security/ui.h"
+
+// Code generated by PDL does not allow us ot do || and && operations on bits
+// efficiently. Use those masks on fields requiring them until this is solved
+constexpr uint8_t AuthReqMaskBondingFlag = 0x01;
+constexpr uint8_t AuthReqMaskMitm = 0x02;
+constexpr uint8_t AuthReqMaskSc = 0x04;
+constexpr uint8_t AuthReqMaskKeypress = 0x08;
+constexpr uint8_t AuthReqMaskCt2 = 0x10;
+
+constexpr uint8_t KeyMaskEnc = 0x01;
+constexpr uint8_t KeyMaskId = 0x02;
+constexpr uint8_t KeyMaskSign = 0x04;
+constexpr uint8_t KeyMaskLink = 0x08;
+
+using bluetooth::hci::EncryptionChangeView;
+using bluetooth::hci::EncryptionKeyRefreshCompleteView;
+
+namespace bluetooth {
+namespace security {
+
+using crypto_toolbox::Octet16;
+
+/* This class represents an event send from other subsystems into SMP Pairing Handler,
+ * i.e. user request from the UI, L2CAP or HCI interaction */
+class PairingEvent {
+ public:
+  enum TYPE { EXIT, L2CAP, HCI_EVENT, UI };
+  TYPE type;
+
+  std::optional<CommandView> l2cap_packet;
+
+  std::optional<hci::EventPacketView> hci_event;
+
+  enum UI_ACTION_TYPE { PAIRING_ACCEPTED, CONFIRM_YESNO, PASSKEY };
+  UI_ACTION_TYPE ui_action;
+  uint32_t ui_value;
+
+  PairingEvent(TYPE type) : type(type) {}
+  PairingEvent(CommandView l2cap_packet) : type(L2CAP), l2cap_packet(l2cap_packet) {}
+  PairingEvent(UI_ACTION_TYPE ui_action, uint32_t ui_value) : type(UI), ui_action(ui_action), ui_value(ui_value) {}
+  PairingEvent(hci::EventPacketView hci_event) : type(HCI_EVENT), hci_event(hci_event) {}
+};
+
+constexpr int SMP_TIMEOUT = 30;
+
+using CommandViewOrFailure = std::variant<CommandView, PairingFailure>;
+using Phase1Result = std::pair<PairingRequestView /* pairning_request*/, PairingResponseView /* pairing_response */>;
+using Phase1ResultOrFailure = std::variant<PairingFailure, Phase1Result>;
+using KeyExchangeResult =
+    std::tuple<EcdhPublicKey /* PKa */, EcdhPublicKey /* PKb */, std::array<uint8_t, 32> /*dhkey*/>;
+using Stage1Result = std::tuple<Octet16, Octet16, Octet16, Octet16>;
+using Stage1ResultOrFailure = std::variant<PairingFailure, Stage1Result>;
+using Stage2ResultOrFailure = std::variant<PairingFailure, Octet16 /* LTK */>;
+using DistributedKeysOrFailure = std::variant<PairingFailure, DistributedKeys, std::monostate>;
+
+using LegacyStage1Result = Octet16 /*TK*/;
+using LegacyStage1ResultOrFailure = std::variant<PairingFailure, LegacyStage1Result>;
+using StkOrFailure = std::variant<PairingFailure, Octet16 /* STK */>;
+
+/* PairingHandlerLe takes care of the Pairing process. Pairing is strictly defined
+ * exchange of messages and UI interactions, divided into PHASES.
+ *
+ * Each PairingHandlerLe have a thread executing |PairingMain| method. Thread is
+ * blocked when waiting for UI/L2CAP/HCI interactions, and moves through all the
+ * phases.
+ */
+class PairingHandlerLe {
+ public:
+  // This is the phase of pairing as defined in BT Spec (with exception of
+  // accept prompt)
+  // * ACCEPT_PROMPT - we're waiting for the user to accept remotely initiated pairing
+  // * PHASE1 - feature exchange
+  // * PHASE2 - authentication
+  // * PHASE3 - key exchange
+  enum PAIRING_PHASE { ACCEPT_PROMPT, PHASE1, PHASE2, PHASE3 };
+  PAIRING_PHASE phase;
+
+  // All the knowledge to initiate the pairing process must be passed into this function
+  PairingHandlerLe(PAIRING_PHASE phase, InitialInformations informations)
+      : phase(phase), queue_guard(), thread_(&PairingHandlerLe::PairingMain, this, informations) {}
+
+  ~PairingHandlerLe() {
+    SendExitSignal();
+    // we need ot check if thread is joinable, because tests call join form
+    // within WaitUntilPairingFinished
+    if (thread_.joinable()) thread_.join();
+  }
+
+  void PairingMain(InitialInformations i);
+
+  Phase1ResultOrFailure ExchangePairingFeature(const InitialInformations& i);
+
+  void SendL2capPacket(const InitialInformations& i, std::unique_ptr<bluetooth::security::CommandBuilder> command) {
+    i.proper_l2cap_interface->Enqueue(std::move(command), i.l2cap_handler);
+  }
+
+  void SendHciLeStartEncryption(const InitialInformations& i, uint16_t conn_handle, const std::array<uint8_t, 8>& rand,
+                                const uint16_t& ediv, const Octet16& ltk) {
+    i.le_security_interface->EnqueueCommand(hci::LeStartEncryptionBuilder::Create(conn_handle, rand, ediv, ltk),
+                                            common::BindOnce([](hci::CommandStatusView) {
+                                              // TODO: handle command status. It's important - can show we are not
+                                              // connected any more.
+                                            }),
+                                            nullptr);
+  }
+
+  std::variant<PairingFailure, EncryptionChangeView, EncryptionKeyRefreshCompleteView> WaitEncryptionChanged() {
+    PairingEvent e = WaitForEvent();
+    if (e.type != PairingEvent::HCI_EVENT) return PairingFailure("Was expecting HCI event but received something else");
+
+    if (!e.hci_event->IsValid()) return PairingFailure("Received invalid HCI event");
+
+    if (e.hci_event->GetEventCode() == hci::EventCode::ENCRYPTION_CHANGE) {
+      EncryptionChangeView enc_chg_packet = EncryptionChangeView::Create(*e.hci_event);
+      if (!enc_chg_packet.IsValid()) {
+        return PairingFailure("Invalid EncryptionChange packet received");
+      }
+      return enc_chg_packet;
+    }
+
+    if (e.hci_event->GetEventCode() == hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE) {
+      hci::EncryptionKeyRefreshCompleteView enc_packet = EncryptionKeyRefreshCompleteView::Create(*e.hci_event);
+      if (!enc_packet.IsValid()) {
+        return PairingFailure("Invalid EncryptionChange packet received");
+      }
+      return enc_packet;
+    }
+
+    return PairingFailure("Was expecting Encryption Change or Key Refresh Complete but received something else");
+  }
+
+  inline bool IAmMaster(const InitialInformations& i) {
+    return i.my_role == hci::Role::MASTER;
+  }
+
+  /* This function generates data that should be passed to remote device, except
+     the private key. */
+  static MyOobData GenerateOobData() {
+    MyOobData data;
+    std::tie(data.private_key, data.public_key) = GenerateECDHKeyPair();
+
+    data.r = GenerateRandom<16>();
+    data.c = crypto_toolbox::f4(data.public_key.x.data(), data.public_key.x.data(), data.r, 0);
+    return data;
+  }
+
+  std::variant<PairingFailure, KeyExchangeResult> ExchangePublicKeys(const InitialInformations& i,
+                                                                     OobDataFlag remote_have_oob_data);
+
+  Stage1ResultOrFailure DoSecureConnectionsStage1(const InitialInformations& i, const EcdhPublicKey& PKa,
+                                                  const EcdhPublicKey& PKb, const PairingRequestView& pairing_request,
+                                                  const PairingResponseView& pairing_response);
+
+  Stage1ResultOrFailure SecureConnectionsNumericComparison(const InitialInformations& i, const EcdhPublicKey& PKa,
+                                                           const EcdhPublicKey& PKb);
+
+  Stage1ResultOrFailure SecureConnectionsJustWorks(const InitialInformations& i, const EcdhPublicKey& PKa,
+                                                   const EcdhPublicKey& PKb);
+
+  Stage1ResultOrFailure SecureConnectionsPasskeyEntry(const InitialInformations& i, const EcdhPublicKey& PKa,
+                                                      const EcdhPublicKey& PKb, IoCapability my_iocaps,
+                                                      IoCapability remote_iocaps);
+
+  Stage1ResultOrFailure SecureConnectionsOutOfBand(const InitialInformations& i, const EcdhPublicKey& Pka,
+                                                   const EcdhPublicKey& Pkb, OobDataFlag my_oob_flag,
+                                                   OobDataFlag remote_oob_flag);
+
+  Stage2ResultOrFailure DoSecureConnectionsStage2(const InitialInformations& i, const EcdhPublicKey& PKa,
+                                                  const EcdhPublicKey& PKb, const PairingRequestView& pairing_request,
+                                                  const PairingResponseView& pairing_response,
+                                                  const Stage1Result stage1result,
+                                                  const std::array<uint8_t, 32>& dhkey);
+
+  DistributedKeysOrFailure DistributeKeys(const InitialInformations& i, const PairingResponseView& pairing_response);
+
+  DistributedKeysOrFailure ReceiveKeys(const uint8_t& keys_i_receive);
+
+  LegacyStage1ResultOrFailure DoLegacyStage1(const InitialInformations& i, const PairingRequestView& pairing_request,
+                                             const PairingResponseView& pairing_response);
+  LegacyStage1ResultOrFailure LegacyOutOfBand(const InitialInformations& i);
+  LegacyStage1ResultOrFailure LegacyJustWorks();
+  LegacyStage1ResultOrFailure LegacyPasskeyEntry(const InitialInformations& i, const IoCapability& my_iocaps,
+                                                 const IoCapability& remote_iocaps);
+  StkOrFailure DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request,
+                              const PairingResponseView& pairing_response, const Octet16& tk);
+
+  void SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv,
+                std::array<uint8_t, 8> rand, Octet16 irk, Address identity_address, AddrType identity_addres_type,
+                Octet16 signature_key);
+
+  /* This can be called from any thread to immediately finish the pairing in progress. */
+  void SendExitSignal() {
+    {
+      std::unique_lock<std::mutex> lock(queue_guard);
+      queue.push(PairingEvent(PairingEvent::EXIT));
+    }
+    pairing_thread_blocker_.notify_one();
+  }
+
+  /* SMP Command received from remote device */
+  void OnCommandView(CommandView packet) {
+    {
+      std::unique_lock<std::mutex> lock(queue_guard);
+      queue.push(PairingEvent(std::move(packet)));
+    }
+    pairing_thread_blocker_.notify_one();
+  }
+
+  /* SMP Command received from remote device */
+  void OnHciEvent(hci::EventPacketView hci_event) {
+    {
+      std::unique_lock<std::mutex> lock(queue_guard);
+      queue.push(PairingEvent(std::move(hci_event)));
+    }
+    pairing_thread_blocker_.notify_one();
+  }
+
+  /* Interaction from user */
+  void OnUiAction(PairingEvent::UI_ACTION_TYPE ui_action, uint32_t ui_value) {
+    {
+      std::unique_lock<std::mutex> lock(queue_guard);
+      queue.push(PairingEvent(ui_action, ui_value));
+    }
+    pairing_thread_blocker_.notify_one();
+  }
+
+  /* Blocks the pairing process until some external interaction, or timeout happens */
+  PairingEvent WaitForEvent() {
+    std::unique_lock<std::mutex> lock(queue_guard);
+    do {
+      if (!queue.empty()) {
+        PairingEvent e = queue.front();
+        queue.pop();
+        return e;
+      }
+      // This releases the lock while blocking.
+      if (pairing_thread_blocker_.wait_for(lock, std::chrono::seconds(SMP_TIMEOUT)) == std::cv_status::timeout) {
+        return PairingEvent(PairingEvent::EXIT);
+      }
+
+    } while (true);
+  }
+
+  std::optional<PairingEvent> WaitUiPairingAccept() {
+    PairingEvent e = WaitForEvent();
+    if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::PAIRING_ACCEPTED) {
+      return e;
+    } else {
+      return std::nullopt;
+    }
+  }
+
+  std::optional<PairingEvent> WaitUiConfirmYesNo() {
+    PairingEvent e = WaitForEvent();
+    if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::CONFIRM_YESNO) {
+      return e;
+    } else {
+      return std::nullopt;
+    }
+  }
+
+  std::optional<PairingEvent> WaitUiPasskey() {
+    PairingEvent e = WaitForEvent();
+    if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::PASSKEY) {
+      return e;
+    } else {
+      return std::nullopt;
+    }
+  }
+
+  template <Code C>
+  struct CodeToPacketView;
+  template <>
+  struct CodeToPacketView<Code::PAIRING_REQUEST> {
+    typedef PairingRequestView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_RESPONSE> {
+    typedef PairingResponseView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_CONFIRM> {
+    typedef PairingConfirmView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_RANDOM> {
+    typedef PairingRandomView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_FAILED> {
+    typedef PairingFailedView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::ENCRYPTION_INFORMATION> {
+    typedef EncryptionInformationView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::MASTER_IDENTIFICATION> {
+    typedef MasterIdentificationView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::IDENTITY_INFORMATION> {
+    typedef IdentityInformationView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::IDENTITY_ADDRESS_INFORMATION> {
+    typedef IdentityAddressInformationView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::SIGNING_INFORMATION> {
+    typedef SigningInformationView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::SECURITY_REQUEST> {
+    typedef SecurityRequestView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_PUBLIC_KEY> {
+    typedef PairingPublicKeyView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_DH_KEY_CHECK> {
+    typedef PairingDhKeyCheckView type;
+  };
+  template <>
+  struct CodeToPacketView<Code::PAIRING_KEYPRESS_NOTIFICATION> {
+    typedef PairingKeypressNotificationView type;
+  };
+
+  template <Code CODE>
+  std::variant<typename CodeToPacketView<CODE>::type, PairingFailure> WaitPacket() {
+    PairingEvent e = WaitForEvent();
+    switch (e.type) {
+      case PairingEvent::EXIT:
+        return PairingFailure(
+            /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received EXIT instead");
+
+      case PairingEvent::HCI_EVENT:
+        return PairingFailure(
+            /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received HCI_EVENT instead");
+
+      case PairingEvent::UI:
+        return PairingFailure(
+            /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received UI instead");
+
+      case PairingEvent::L2CAP: {
+        auto l2cap_packet = e.l2cap_packet.value();
+        if (!l2cap_packet.IsValid()) {
+          return PairingFailure("Malformed L2CAP packet received!");
+        }
+
+        const auto& received_code = l2cap_packet.GetCode();
+        if (received_code != CODE) {
+          if (received_code == Code::PAIRING_FAILED) {
+            auto pkt = PairingFailedView::Create(l2cap_packet);
+            if (!pkt.IsValid()) return PairingFailure("Malformed " + CodeText(CODE) + " packet");
+            return PairingFailure(/*FROM_HERE,*/
+                                  "Was expecting " + CodeText(CODE) + ", but received PAIRING_FAILED instead",
+                                  pkt.GetReason());
+          }
+
+          return PairingFailure(/*FROM_HERE,*/
+                                "Was expecting " + CodeText(CODE) + ", but received " + CodeText(received_code) +
+                                    " instead",
+                                received_code);
+        }
+
+        auto pkt = CodeToPacketView<CODE>::type::Create(l2cap_packet);
+        if (!pkt.IsValid()) return PairingFailure("Malformed " + CodeText(CODE) + " packet");
+        return pkt;
+      }
+    }
+  }
+
+  auto WaitPairingRequest() {
+    return WaitPacket<Code::PAIRING_REQUEST>();
+  }
+
+  auto WaitPairingResponse() {
+    return WaitPacket<Code::PAIRING_RESPONSE>();
+  }
+
+  auto WaitPairingConfirm() {
+    return WaitPacket<Code::PAIRING_CONFIRM>();
+  }
+
+  auto WaitPairingRandom() {
+    return WaitPacket<Code::PAIRING_RANDOM>();
+  }
+
+  auto WaitPairingPublicKey() {
+    return WaitPacket<Code::PAIRING_PUBLIC_KEY>();
+  }
+
+  auto WaitPairingDHKeyCheck() {
+    return WaitPacket<Code::PAIRING_DH_KEY_CHECK>();
+  }
+
+  auto WaitEncryptionInformationRequest() {
+    return WaitPacket<Code::ENCRYPTION_INFORMATION>();
+  }
+
+  auto WaitEncryptionInformation() {
+    return WaitPacket<Code::ENCRYPTION_INFORMATION>();
+  }
+
+  auto WaitMasterIdentification() {
+    return WaitPacket<Code::MASTER_IDENTIFICATION>();
+  }
+
+  auto WaitIdentityInformation() {
+    return WaitPacket<Code::IDENTITY_INFORMATION>();
+  }
+
+  auto WaitIdentityAddressInformation() {
+    return WaitPacket<Code::IDENTITY_ADDRESS_INFORMATION>();
+  }
+
+  auto WaitSigningInformation() {
+    return WaitPacket<Code::SIGNING_INFORMATION>();
+  }
+
+  template <size_t SIZE>
+  static std::array<uint8_t, SIZE> GenerateRandom() {
+    // TODO:  We need a proper  random number generator here.
+    // use current time as seed for random generator
+    std::srand(std::time(nullptr));
+    std::array<uint8_t, SIZE> r;
+    for (size_t i = 0; i < SIZE; i++) r[i] = std::rand();
+    return r;
+  }
+
+  uint32_t GenerateRandom() {
+    // TODO:  We need a proper  random number generator here.
+    // use current time as seed for random generator
+    std::srand(std::time(nullptr));
+    return std::rand();
+  }
+
+  /* This is just for test, never use in production code! */
+  void WaitUntilPairingFinished() {
+    thread_.join();
+  }
+
+ private:
+  std::condition_variable pairing_thread_blocker_;
+
+  std::mutex queue_guard;
+  std::queue<PairingEvent> queue;
+
+  std::thread thread_;
+};
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_legacy.cc b/gd/security/pairing_handler_le_legacy.cc
new file mode 100644
index 0000000..0c3a73b
--- /dev/null
+++ b/gd/security/pairing_handler_le_legacy.cc
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ *  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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+LegacyStage1ResultOrFailure PairingHandlerLe::DoLegacyStage1(const InitialInformations& i,
+                                                             const PairingRequestView& pairing_request,
+                                                             const PairingResponseView& pairing_response) {
+  if (((pairing_request.GetAuthReq() | pairing_response.GetAuthReq()) & AuthReqMaskMitm) == 0) {
+    // If both devices have not set MITM option, Just Works shall be used
+    return LegacyJustWorks();
+  }
+
+  if (pairing_request.GetOobDataFlag() == OobDataFlag::PRESENT &&
+      pairing_response.GetOobDataFlag() == OobDataFlag::PRESENT) {
+    // OobDataFlag remote_oob_flag = IAmMaster(i) ? pairing_response.GetOobDataFlag() :
+    // pairing_request.GetOobDataFlag(); OobDataFlag my_oob_flag = IAmMaster(i) ? pairing_request.GetOobDataFlag() :
+    // pairing_response.GetOobDataFlag();
+    return LegacyOutOfBand(i);
+  }
+
+  const auto& iom = pairing_request.GetIoCapability();
+  const auto& ios = pairing_response.GetIoCapability();
+
+  if (iom == IoCapability::NO_INPUT_NO_OUTPUT || ios == IoCapability::NO_INPUT_NO_OUTPUT) {
+    return LegacyJustWorks();
+  }
+
+  if ((iom == IoCapability::DISPLAY_ONLY || iom == IoCapability::DISPLAY_YES_NO) &&
+      (ios == IoCapability::DISPLAY_ONLY || ios == IoCapability::DISPLAY_YES_NO)) {
+    return LegacyJustWorks();
+  }
+
+  // This if() should not be needed, these are only combinations left.
+  if (iom == IoCapability::KEYBOARD_DISPLAY || iom == IoCapability::KEYBOARD_ONLY ||
+      ios == IoCapability::KEYBOARD_DISPLAY || ios == IoCapability::KEYBOARD_ONLY) {
+    IoCapability my_iocaps = IAmMaster(i) ? iom : ios;
+    IoCapability remote_iocaps = IAmMaster(i) ? ios : iom;
+    return LegacyPasskeyEntry(i, my_iocaps, remote_iocaps);
+  }
+
+  // We went through all possble combinations.
+  LOG_ALWAYS_FATAL("This should never happen");
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyJustWorks() {
+  LOG_INFO("Legacy Just Works start");
+  return Octet16{0};
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyPasskeyEntry(const InitialInformations& i,
+                                                                 const IoCapability& my_iocaps,
+                                                                 const IoCapability& remote_iocaps) {
+  bool i_am_displaying = false;
+  if (my_iocaps == IoCapability::DISPLAY_ONLY || my_iocaps == IoCapability::DISPLAY_YES_NO) {
+    i_am_displaying = true;
+  } else if (IAmMaster(i) && remote_iocaps == IoCapability::KEYBOARD_DISPLAY &&
+             my_iocaps == IoCapability::KEYBOARD_DISPLAY) {
+    i_am_displaying = true;
+  } else if (my_iocaps == IoCapability::KEYBOARD_DISPLAY && remote_iocaps == IoCapability::KEYBOARD_ONLY) {
+    i_am_displaying = true;
+  }
+
+  LOG_INFO("Passkey Entry start %s", i_am_displaying ? "displaying" : "accepting");
+
+  uint32_t passkey;
+  if (i_am_displaying) {
+    // generate passkey in a valid range
+    passkey = GenerateRandom();
+    passkey &= 0x0fffff; /* maximum 20 significant bits */
+    constexpr uint32_t PASSKEY_MAX = 999999;
+    if (passkey > PASSKEY_MAX) passkey >>= 1;
+
+    i.ui_handler->DisplayConfirmValue(passkey);
+  } else {
+    i.ui_handler->DisplayEnterPasskeyDialog();
+    std::optional<PairingEvent> response = WaitUiPasskey();
+    if (!response) return PairingFailure("Passkey did not arrive!");
+
+    passkey = response->ui_value;
+  }
+
+  Octet16 tk{0};
+  tk[0] = (uint8_t)(passkey);
+  tk[1] = (uint8_t)(passkey >> 8);
+  tk[2] = (uint8_t)(passkey >> 16);
+  tk[3] = (uint8_t)(passkey >> 24);
+
+  LOG_INFO("Passkey Entry finish");
+  return tk;
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyOutOfBand(const InitialInformations& i) {
+  return i.remote_oob_data->security_manager_tk_value;
+}
+
+StkOrFailure PairingHandlerLe::DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request,
+                                              const PairingResponseView& pairing_response, const Octet16& tk) {
+  LOG_INFO("Legacy Step 2 start");
+  std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
+  std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
+
+  Octet16 mrand, srand;
+  if (IAmMaster(i)) {
+    mrand = GenerateRandom<16>();
+
+    // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " mrand = " << base::HexEncode(mrand.data(), mrand.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+    Octet16 mconfirm = crypto_toolbox::c1(
+        tk, mrand, preq.data(), pres.data(), (uint8_t)i.my_connection_address.GetAddressType(),
+        i.my_connection_address.GetAddress().address, (uint8_t)i.remote_connection_address.GetAddressType(),
+        i.remote_connection_address.GetAddress().address);
+
+    LOG_INFO("Master sends Mconfirm");
+    SendL2capPacket(i, PairingConfirmBuilder::Create(mconfirm));
+
+    LOG_INFO("Master waits for the Sconfirm");
+    auto sconfirm_pkt = WaitPairingConfirm();
+    if (std::holds_alternative<PairingFailure>(sconfirm_pkt)) {
+      return std::get<PairingFailure>(sconfirm_pkt);
+    }
+    Octet16 sconfirm = std::get<PairingConfirmView>(sconfirm_pkt).GetConfirmValue();
+
+    LOG_INFO("Master sends Mrand");
+    SendL2capPacket(i, PairingRandomBuilder::Create(mrand));
+
+    LOG_INFO("Master waits for Srand");
+    auto random_pkt = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random_pkt)) {
+      return std::get<PairingFailure>(random_pkt);
+    }
+    srand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
+
+    // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " srand = " << base::HexEncode(srand.data(), srand.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+    Octet16 sconfirm_generated = crypto_toolbox::c1(
+        tk, srand, preq.data(), pres.data(), (uint8_t)i.my_connection_address.GetAddressType(),
+        i.my_connection_address.GetAddress().address, (uint8_t)i.remote_connection_address.GetAddressType(),
+        i.remote_connection_address.GetAddress().address);
+
+    if (sconfirm != sconfirm_generated) {
+      LOG_INFO("sconfirm does not match generated value");
+
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+      return PairingFailure("sconfirm does not match generated value");
+    }
+  } else {
+    srand = GenerateRandom<16>();
+
+    std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
+    std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
+
+    Octet16 sconfirm = crypto_toolbox::c1(
+        tk, srand, preq.data(), pres.data(), (uint8_t)i.remote_connection_address.GetAddressType(),
+        i.remote_connection_address.GetAddress().address, (uint8_t)i.my_connection_address.GetAddressType(),
+        i.my_connection_address.GetAddress().address);
+
+    LOG_INFO("Slave waits for the Mconfirm");
+    auto mconfirm_pkt = WaitPairingConfirm();
+    if (std::holds_alternative<PairingFailure>(mconfirm_pkt)) {
+      return std::get<PairingFailure>(mconfirm_pkt);
+    }
+    Octet16 mconfirm = std::get<PairingConfirmView>(mconfirm_pkt).GetConfirmValue();
+
+    LOG_INFO("Slave sends Sconfirm");
+    SendL2capPacket(i, PairingConfirmBuilder::Create(sconfirm));
+
+    LOG_INFO("Slave waits for Mrand");
+    auto random_pkt = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random_pkt)) {
+      return std::get<PairingFailure>(random_pkt);
+    }
+    mrand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
+
+    // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " mrand = " << base::HexEncode(mrand.data(), mrand.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+    // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+    // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+    Octet16 mconfirm_generated = crypto_toolbox::c1(
+        tk, mrand, preq.data(), pres.data(), (uint8_t)i.remote_connection_address.GetAddressType(),
+        i.remote_connection_address.GetAddress().address, (uint8_t)i.my_connection_address.GetAddressType(),
+        i.my_connection_address.GetAddress().address);
+
+    if (mconfirm != mconfirm_generated) {
+      LOG_INFO("mconfirm does not match generated value");
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+      return PairingFailure("mconfirm does not match generated value");
+    }
+
+    LOG_INFO("Slave sends Srand");
+    SendL2capPacket(i, PairingRandomBuilder::Create(srand));
+  }
+
+  LOG_INFO("Legacy stage 2 finish");
+
+  /* STK */
+  return crypto_toolbox::s1(tk, srand, mrand);
+}
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_secure_connections.cc b/gd/security/pairing_handler_le_secure_connections.cc
new file mode 100644
index 0000000..f5b0a0f
--- /dev/null
+++ b/gd/security/pairing_handler_le_secure_connections.cc
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ *  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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+std::variant<PairingFailure, KeyExchangeResult> PairingHandlerLe::ExchangePublicKeys(const InitialInformations& i,
+                                                                                     OobDataFlag remote_have_oob_data) {
+  // Generate ECDH, or use one that was used for OOB data
+  const auto [private_key, public_key] = (remote_have_oob_data == OobDataFlag::NOT_PRESENT || !i.my_oob_data)
+                                             ? GenerateECDHKeyPair()
+                                             : std::make_pair(i.my_oob_data->private_key, i.my_oob_data->public_key);
+
+  LOG_INFO("Public key exchange start");
+  std::unique_ptr<PairingPublicKeyBuilder> myPublicKey = PairingPublicKeyBuilder::Create(public_key.x, public_key.y);
+
+  if (!ValidateECDHPoint(public_key)) {
+    LOG_ERROR("Can't validate my own public key!!!");
+    return PairingFailure("Can't validate my own public key");
+  }
+
+  if (IAmMaster(i)) {
+    // Send pairing public key
+    LOG_INFO("Master sends out public key");
+    SendL2capPacket(i, std::move(myPublicKey));
+  }
+
+  LOG_INFO(" Waiting for Public key...");
+  auto response = WaitPairingPublicKey();
+  LOG_INFO(" Received public key");
+  if (std::holds_alternative<PairingFailure>(response)) {
+    return std::get<PairingFailure>(response);
+  }
+
+  EcdhPublicKey remote_public_key;
+  auto ppkv = std::get<PairingPublicKeyView>(response);
+  remote_public_key.x = ppkv.GetPublicKeyX();
+  remote_public_key.y = ppkv.GetPublicKeyY();
+  LOG_INFO("Received Public key from remote");
+
+  // validate received public key
+  if (!ValidateECDHPoint(remote_public_key)) {
+    // TODO: Spec is unclear what should happend when the point is not on
+    // the correct curve: A device that detects an invalid public key from
+    // the peer at any point during the LE Secure Connections pairing
+    // process shall not use the resulting LTK, if any.
+    LOG_INFO("Can't validate remote public key");
+    return PairingFailure("Can't validate remote public key");
+  }
+
+  if (!IAmMaster(i)) {
+    LOG_INFO("Slave sends out public key");
+    // Send pairing public key
+    SendL2capPacket(i, std::move(myPublicKey));
+  }
+
+  LOG_INFO("Public key exchange finish");
+
+  std::array<uint8_t, 32> dhkey = ComputeDHKey(private_key, remote_public_key);
+
+  const EcdhPublicKey& PKa = IAmMaster(i) ? public_key : remote_public_key;
+  const EcdhPublicKey& PKb = IAmMaster(i) ? remote_public_key : public_key;
+
+  return KeyExchangeResult{PKa, PKb, dhkey};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage1(const InitialInformations& i,
+                                                                  const EcdhPublicKey& PKa, const EcdhPublicKey& PKb,
+                                                                  const PairingRequestView& pairing_request,
+                                                                  const PairingResponseView& pairing_response) {
+  if ((pairing_request.GetAuthReq() & pairing_response.GetAuthReq() & AuthReqMaskMitm) == 0) {
+    // If both devices have not set MITM option, Just Works shall be used
+    return SecureConnectionsJustWorks(i, PKa, PKb);
+  }
+
+  if (pairing_request.GetOobDataFlag() == OobDataFlag::PRESENT ||
+      pairing_response.GetOobDataFlag() == OobDataFlag::PRESENT) {
+    OobDataFlag remote_oob_flag = IAmMaster(i) ? pairing_response.GetOobDataFlag() : pairing_request.GetOobDataFlag();
+    OobDataFlag my_oob_flag = IAmMaster(i) ? pairing_request.GetOobDataFlag() : pairing_response.GetOobDataFlag();
+    return SecureConnectionsOutOfBand(i, PKa, PKb, my_oob_flag, remote_oob_flag);
+  }
+
+  const auto& iom = pairing_request.GetIoCapability();
+  const auto& ios = pairing_response.GetIoCapability();
+
+  if ((iom == IoCapability::KEYBOARD_DISPLAY || iom == IoCapability::DISPLAY_YES_NO) &&
+      (ios == IoCapability::KEYBOARD_DISPLAY || ios == IoCapability::DISPLAY_YES_NO)) {
+    return SecureConnectionsNumericComparison(i, PKa, PKb);
+  }
+
+  if (iom == IoCapability::NO_INPUT_NO_OUTPUT || ios == IoCapability::NO_INPUT_NO_OUTPUT) {
+    return SecureConnectionsJustWorks(i, PKa, PKb);
+  }
+
+  if ((iom == IoCapability::DISPLAY_ONLY || iom == IoCapability::DISPLAY_YES_NO) &&
+      (ios == IoCapability::DISPLAY_ONLY || ios == IoCapability::DISPLAY_YES_NO)) {
+    return SecureConnectionsJustWorks(i, PKa, PKb);
+  }
+
+  IoCapability my_iocaps = IAmMaster(i) ? iom : ios;
+  IoCapability remote_iocaps = IAmMaster(i) ? ios : iom;
+  return SecureConnectionsPasskeyEntry(i, PKa, PKb, my_iocaps, remote_iocaps);
+}
+
+Stage2ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage2(const InitialInformations& i,
+                                                                  const EcdhPublicKey& PKa, const EcdhPublicKey& PKb,
+                                                                  const PairingRequestView& pairing_request,
+                                                                  const PairingResponseView& pairing_response,
+                                                                  const Stage1Result stage1result,
+                                                                  const std::array<uint8_t, 32>& dhkey) {
+  LOG_INFO("Authentication stage 2 started");
+
+  auto [Na, Nb, ra, rb] = stage1result;
+
+  // 2.3.5.6.5 Authentication stage 2 long term key calculation
+  uint8_t a[7];
+  uint8_t b[7];
+
+  if (IAmMaster(i)) {
+    memcpy(a, i.my_connection_address.GetAddress().address, 6);
+    a[6] = (uint8_t)i.my_connection_address.GetAddressType();
+    memcpy(b, i.remote_connection_address.GetAddress().address, 6);
+    b[6] = (uint8_t)i.remote_connection_address.GetAddressType();
+  } else {
+    memcpy(a, i.remote_connection_address.GetAddress().address, 6);
+    a[6] = (uint8_t)i.remote_connection_address.GetAddressType();
+    memcpy(b, i.my_connection_address.GetAddress().address, 6);
+    b[6] = (uint8_t)i.my_connection_address.GetAddressType();
+  }
+
+  Octet16 ltk, mac_key;
+  crypto_toolbox::f5((uint8_t*)dhkey.data(), Na, Nb, a, b, &mac_key, &ltk);
+
+  // DHKey exchange and check
+
+  std::array<uint8_t, 3> iocapA{static_cast<uint8_t>(pairing_request.GetIoCapability()),
+                                static_cast<uint8_t>(pairing_request.GetOobDataFlag()), pairing_request.GetAuthReq()};
+  std::array<uint8_t, 3> iocapB{static_cast<uint8_t>(pairing_response.GetIoCapability()),
+                                static_cast<uint8_t>(pairing_response.GetOobDataFlag()), pairing_response.GetAuthReq()};
+
+  // LOG(INFO) << +(IAmMaster(i)) << " LTK = " << base::HexEncode(ltk.data(), ltk.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " MAC_KEY = " << base::HexEncode(mac_key.data(), mac_key.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " Na = " << base::HexEncode(Na.data(), Na.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " Nb = " << base::HexEncode(Nb.data(), Nb.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " ra = " << base::HexEncode(ra.data(), ra.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " rb = " << base::HexEncode(rb.data(), rb.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " iocapA = " << base::HexEncode(iocapA.data(), iocapA.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " iocapB = " << base::HexEncode(iocapB.data(), iocapB.size());
+  // LOG(INFO) << +(IAmMaster(i)) << " a = " << base::HexEncode(a, 7);
+  // LOG(INFO) << +(IAmMaster(i)) << " b = " << base::HexEncode(b, 7);
+
+  Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b);
+
+  Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a);
+
+  if (IAmMaster(i)) {
+    // send Pairing DHKey Check
+    SendL2capPacket(i, PairingDhKeyCheckBuilder::Create(Ea));
+
+    auto response = WaitPairingDHKeyCheck();
+    if (std::holds_alternative<PairingFailure>(response)) {
+      return std::get<PairingFailure>(response);
+    }
+
+    if (std::get<PairingDhKeyCheckView>(response).GetDhKeyCheck() != Eb) {
+      LOG_INFO("Ea != Eb, aborting!");
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::DHKEY_CHECK_FAILED));
+      return PairingFailure("Ea != Eb");
+    }
+  } else {
+    auto response = WaitPairingDHKeyCheck();
+    if (std::holds_alternative<PairingFailure>(response)) {
+      return std::get<PairingFailure>(response);
+    }
+
+    if (std::get<PairingDhKeyCheckView>(response).GetDhKeyCheck() != Ea) {
+      LOG_INFO("Ea != Eb, aborting!");
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::DHKEY_CHECK_FAILED));
+      return PairingFailure("Ea != Eb");
+    }
+
+    // send Pairing DHKey Check
+    SendL2capPacket(i, PairingDhKeyCheckBuilder::Create(Eb));
+  }
+
+  LOG_INFO("Authentication stage 2 (DHKey checks) finished");
+  return ltk;
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsOutOfBand(const InitialInformations& i,
+                                                                   const EcdhPublicKey& Pka, const EcdhPublicKey& Pkb,
+                                                                   OobDataFlag my_oob_flag,
+                                                                   OobDataFlag remote_oob_flag) {
+  LOG_INFO("Out Of Band start");
+
+  Octet16 zeros{0};
+  Octet16 localR = (remote_oob_flag == OobDataFlag::PRESENT && i.my_oob_data) ? i.my_oob_data->r : zeros;
+  Octet16 remoteR;
+
+  if (my_oob_flag == OobDataFlag::NOT_PRESENT || (my_oob_flag == OobDataFlag::PRESENT && !i.remote_oob_data)) {
+    /* we have send the OOB data, but not received them. remote will check if
+     * C value is correct */
+    remoteR = zeros;
+  } else {
+    remoteR = i.remote_oob_data->le_sc_r;
+    Octet16 remoteC = i.remote_oob_data->le_sc_c;
+
+    Octet16 remoteC2;
+    if (IAmMaster(i)) {
+      remoteC2 = crypto_toolbox::f4((uint8_t*)Pkb.x.data(), (uint8_t*)Pkb.x.data(), remoteR, 0);
+    } else {
+      remoteC2 = crypto_toolbox::f4((uint8_t*)Pka.x.data(), (uint8_t*)Pka.x.data(), remoteR, 0);
+    }
+
+    if (remoteC2 != remoteC) {
+      LOG_ERROR("C_computed != C_from_remote, aborting!");
+      return PairingFailure("C_computed != C_from_remote, aborting");
+    }
+  }
+
+  Octet16 Na, Nb, ra, rb;
+  if (IAmMaster(i)) {
+    ra = localR;
+    rb = remoteR;
+    Na = GenerateRandom<16>();
+    // Send Pairing Random
+    SendL2capPacket(i, PairingRandomBuilder::Create(Na));
+
+    LOG_INFO("Master waits for Nb");
+    auto random = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random)) {
+      return std::get<PairingFailure>(random);
+    }
+    Nb = std::get<PairingRandomView>(random).GetRandomValue();
+  } else {
+    ra = remoteR;
+    rb = localR;
+    Nb = GenerateRandom<16>();
+
+    LOG_INFO("Slave waits for random");
+    auto random = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random)) {
+      return std::get<PairingFailure>(random);
+    }
+    Na = std::get<PairingRandomView>(random).GetRandomValue();
+
+    SendL2capPacket(i, PairingRandomBuilder::Create(Nb));
+  }
+
+  return Stage1Result{Na, Nb, ra, rb};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsPasskeyEntry(const InitialInformations& i,
+                                                                      const EcdhPublicKey& PKa,
+                                                                      const EcdhPublicKey& PKb, IoCapability my_iocaps,
+                                                                      IoCapability remote_iocaps) {
+  LOG_INFO("Passkey Entry start");
+  Octet16 Na, Nb, ra{0}, rb{0};
+
+  uint32_t passkey;
+
+  if (my_iocaps == IoCapability::DISPLAY_ONLY || remote_iocaps == IoCapability::KEYBOARD_ONLY) {
+    // I display
+    passkey = GenerateRandom();
+    passkey &= 0x0fffff; /* maximum 20 significant bytes */
+    constexpr uint32_t PASSKEY_MAX = 999999;
+    while (passkey > PASSKEY_MAX) passkey >>= 1;
+
+    i.ui_handler->DisplayPasskey(passkey);
+
+  } else if (my_iocaps == IoCapability::KEYBOARD_ONLY || remote_iocaps == IoCapability::DISPLAY_ONLY) {
+    i.ui_handler->DisplayEnterPasskeyDialog();
+    std::optional<PairingEvent> response = WaitUiPasskey();
+    if (!response) return PairingFailure("Passkey did not arrive!");
+
+    passkey = response->ui_value;
+
+    /*TODO: shall we send "Keypress Notification" after each key ? This would
+     * have impact on the SMP timeout*/
+
+  } else {
+    LOG(FATAL) << "THIS SHOULD NEVER HAPPEN";
+    return PairingFailure("FATAL!");
+  }
+
+  uint32_t bitmask = 0x01;
+  for (int loop = 0; loop < 20; loop++, bitmask <<= 1) {
+    LOG_INFO("Iteration no %d", loop);
+    bool bit_set = ((bitmask & passkey) != 0);
+    uint8_t ri = bit_set ? 0x81 : 0x80;
+
+    Octet16 Cai, Cbi, Nai, Nbi;
+    if (IAmMaster(i)) {
+      Nai = GenerateRandom<16>();
+
+      Cai = crypto_toolbox::f4((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Nai, ri);
+
+      // Send Pairing Confirm
+      LOG_INFO("Master sends Cai");
+      SendL2capPacket(i, PairingConfirmBuilder::Create(Cai));
+
+      LOG_INFO("Master waits for the Cbi");
+      auto confirm = WaitPairingConfirm();
+      if (std::holds_alternative<PairingFailure>(confirm)) {
+        return std::get<PairingFailure>(confirm);
+      }
+      Cbi = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+      // Send Pairing Random
+      SendL2capPacket(i, PairingRandomBuilder::Create(Nai));
+
+      LOG_INFO("Master waits for Nbi");
+      auto random = WaitPairingRandom();
+      if (std::holds_alternative<PairingFailure>(random)) {
+        return std::get<PairingFailure>(random);
+      }
+      Nbi = std::get<PairingRandomView>(random).GetRandomValue();
+
+      Octet16 Cbi2 = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nbi, ri);
+      if (Cbi != Cbi2) {
+        LOG_INFO("Cai != Cbi, aborting!");
+        SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+        return PairingFailure("Cai != Cbi");
+      }
+    } else {
+      Nbi = GenerateRandom<16>();
+      // Compute confirm
+      Cbi = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nbi, ri);
+
+      LOG_INFO("Slave waits for the Cai");
+      auto confirm = WaitPairingConfirm();
+      if (std::holds_alternative<PairingFailure>(confirm)) {
+        return std::get<PairingFailure>(confirm);
+      }
+      Cai = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+      // Send Pairing Confirm
+      LOG_INFO("Slave sends confirmation");
+      SendL2capPacket(i, PairingConfirmBuilder::Create(Cbi));
+
+      LOG_INFO("Slave waits for random");
+      auto random = WaitPairingRandom();
+      if (std::holds_alternative<PairingFailure>(random)) {
+        return std::get<PairingFailure>(random);
+      }
+      Nai = std::get<PairingRandomView>(random).GetRandomValue();
+
+      Octet16 Cai2 = crypto_toolbox::f4((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Nai, ri);
+      if (Cai != Cai2) {
+        LOG_INFO("Cai != Cai2, aborting!");
+        SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+        return PairingFailure("Cai != Cai2");
+      }
+
+      // Send Pairing Random
+      SendL2capPacket(i, PairingRandomBuilder::Create(Nbi));
+    }
+
+    if (loop == 19) {
+      Na = Nai;
+      Nb = Nbi;
+    }
+  }
+
+  ra[0] = (uint8_t)(passkey);
+  ra[1] = (uint8_t)(passkey >> 8);
+  ra[2] = (uint8_t)(passkey >> 16);
+  ra[3] = (uint8_t)(passkey >> 24);
+  rb = ra;
+
+  return Stage1Result{Na, Nb, ra, rb};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsNumericComparison(const InitialInformations& i,
+                                                                           const EcdhPublicKey& PKa,
+                                                                           const EcdhPublicKey& PKb) {
+  LOG_INFO("Numeric Comparison start");
+  Stage1ResultOrFailure result = SecureConnectionsJustWorks(i, PKa, PKb);
+  if (std::holds_alternative<PairingFailure>(result)) {
+    return std::get<PairingFailure>(result);
+  }
+
+  const auto [Na, Nb, ra, rb] = std::get<Stage1Result>(result);
+
+  uint32_t number_to_display = crypto_toolbox::g2((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Na, Nb);
+
+  i.ui_handler->DisplayConfirmValue(number_to_display);
+
+  std::optional<PairingEvent> confirmyesno = WaitUiConfirmYesNo();
+  if (!confirmyesno || confirmyesno->ui_value == 0) {
+    LOG_INFO("Was expecting the user value confirm");
+    return PairingFailure("Was expecting the user value confirm");
+  }
+
+  return result;
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsJustWorks(const InitialInformations& i,
+                                                                   const EcdhPublicKey& PKa, const EcdhPublicKey& PKb) {
+  Octet16 Ca, Cb, Na, Nb, ra, rb;
+
+  ra = rb = {0};
+
+  if (IAmMaster(i)) {
+    Na = GenerateRandom<16>();
+    LOG_INFO("Master waits for confirmation");
+    auto confirm = WaitPairingConfirm();
+    if (std::holds_alternative<PairingFailure>(confirm)) {
+      return std::get<PairingFailure>(confirm);
+    }
+    Cb = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+    // Send Pairing Random
+    SendL2capPacket(i, PairingRandomBuilder::Create(Na));
+
+    LOG_INFO("Master waits for Random");
+    auto random = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random)) {
+      return std::get<PairingFailure>(random);
+    }
+    Nb = std::get<PairingRandomView>(random).GetRandomValue();
+
+    // Compute confirm
+    Ca = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nb, 0);
+
+    if (Ca != Cb) {
+      LOG_INFO("Ca != Cb, aborting!");
+      SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+      return PairingFailure("Ca != Cb");
+    }
+  } else {
+    Nb = GenerateRandom<16>();
+    // Compute confirm
+    Cb = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nb, 0);
+
+    // Send Pairing Confirm
+    LOG_INFO("Slave sends confirmation");
+    SendL2capPacket(i, PairingConfirmBuilder::Create(Cb));
+
+    LOG_INFO("Slave waits for random");
+    auto random = WaitPairingRandom();
+    if (std::holds_alternative<PairingFailure>(random)) {
+      return std::get<PairingFailure>(random);
+    }
+    Na = std::get<PairingRandomView>(random).GetRandomValue();
+
+    // Send Pairing Random
+    SendL2capPacket(i, PairingRandomBuilder::Create(Nb));
+  }
+
+  return Stage1Result{Na, Nb, ra, rb};
+}
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_unittest.cc b/gd/security/pairing_handler_le_unittest.cc
new file mode 100644
index 0000000..3610700
--- /dev/null
+++ b/gd/security/pairing_handler_le_unittest.cc
@@ -0,0 +1,335 @@
+/******************************************************************************
+ *
+ *  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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::VariantWith;
+
+using bluetooth::security::CommandView;
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+
+CommandView BuilderToView(std::unique_ptr<BasePacketBuilder> builder) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  builder->Serialize(it);
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+  return CommandView::Create(temp_cmd_view);
+}
+
+std::condition_variable outgoing_l2cap_blocker_;
+std::optional<bluetooth::security::CommandView> outgoing_l2cap_packet_;
+
+bool WaitForOutgoingL2capPacket() {
+  std::mutex mutex;
+  std::unique_lock<std::mutex> lock(mutex);
+  if (outgoing_l2cap_blocker_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) {
+    return false;
+  }
+  return true;
+}
+
+class PairingResultHandlerMock {
+ public:
+  MOCK_CONST_METHOD1(OnPairingFinished, void(PairingResultOrFailure));
+};
+
+std::unique_ptr<PairingResultHandlerMock> pairingResult;
+LeSecurityInterfaceMock leSecurityMock;
+UIMock uiMock;
+
+void OnPairingFinished(PairingResultOrFailure r) {
+  if (std::holds_alternative<PairingResult>(r)) {
+    LOG(INFO) << "pairing with " << std::get<PairingResult>(r).connection_address << " finished successfully!";
+  } else {
+    LOG(INFO) << "pairing with ... failed!";
+  }
+  pairingResult->OnPairingFinished(r);
+}
+}  // namespace
+
+class PairingHandlerUnitTest : public testing::Test {
+ protected:
+  void SetUp() {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+
+    bidi_queue_ =
+        std::make_unique<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>>(10);
+    up_buffer_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(bidi_queue_->GetUpEnd());
+
+    bidi_queue_->GetDownEnd()->RegisterDequeue(
+        handler_, common::Bind(&PairingHandlerUnitTest::L2CAP_SendSmp, common::Unretained(this)));
+
+    pairingResult.reset(new PairingResultHandlerMock);
+  }
+  void TearDown() {
+    pairingResult.reset();
+    bidi_queue_->GetDownEnd()->UnregisterDequeue();
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+
+    ::testing::Mock::VerifyAndClearExpectations(&leSecurityMock);
+    ::testing::Mock::VerifyAndClearExpectations(&uiMock);
+  }
+
+  void L2CAP_SendSmp() {
+    std::unique_ptr<packet::BasePacketBuilder> builder = bidi_queue_->GetDownEnd()->TryDequeue();
+
+    outgoing_l2cap_packet_ = BuilderToView(std::move(builder));
+    outgoing_l2cap_packet_->IsValid();
+
+    outgoing_l2cap_blocker_.notify_one();
+  }
+
+ public:
+  os::Thread* thread_;
+  os::Handler* handler_;
+  std::unique_ptr<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>> bidi_queue_;
+  std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_;
+};
+
+InitialInformations initial_informations{
+    .my_role = hci::Role::MASTER,
+    .my_connection_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
+
+    .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                              .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                              .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                              .maximum_encryption_key_size = 16,
+                              .initiator_key_distribution = 0x03,
+                              .responder_key_distribution = 0x03},
+
+    .remotely_initiated = false,
+    .remote_connection_address = {{}, hci::AddressType::RANDOM_DEVICE_ADDRESS},
+    .ui_handler = &uiMock,
+    .le_security_interface = &leSecurityMock,
+    .OnPairingFinished = OnPairingFinished,
+};
+
+TEST_F(PairingHandlerUnitTest, test_phase_1_failure) {
+  initial_informations.proper_l2cap_interface = up_buffer_.get();
+  initial_informations.l2cap_handler = handler_;
+
+  std::unique_ptr<PairingHandlerLe> pairing_handler =
+      std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST);
+
+  EXPECT_CALL(*pairingResult, OnPairingFinished(VariantWith<PairingFailure>(_))).Times(1);
+
+  // SMP will waith for Pairing Response, once bad packet is received, it should stop the Pairing
+  CommandView bad_pairing_response = BuilderToView(PairingRandomBuilder::Create({}));
+  bad_pairing_response.IsValid();
+  pairing_handler->OnCommandView(bad_pairing_response);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_FAILED);
+}
+
+TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) {
+  initial_informations.proper_l2cap_interface = up_buffer_.get();
+  initial_informations.l2cap_handler = handler_;
+
+  // we keep the pairing_handler as unique_ptr to better mimick how it's used
+  // in the real world
+  std::unique_ptr<PairingHandlerLe> pairing_handler =
+      std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST);
+  CommandView pairing_request = outgoing_l2cap_packet_.value();
+
+  auto pairing_response = BuilderToView(
+      PairingResponseBuilder::Create(IoCapability::KEYBOARD_DISPLAY, OobDataFlag::NOT_PRESENT,
+                                     AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03));
+  pairing_handler->OnCommandView(pairing_response);
+  // Phase 1 finished.
+
+  // pairing public key
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(Code::PAIRING_PUBLIC_KEY, outgoing_l2cap_packet_->GetCode());
+  EcdhPublicKey my_public_key;
+  auto ppkv = PairingPublicKeyView::Create(outgoing_l2cap_packet_.value());
+  ppkv.IsValid();
+  my_public_key.x = ppkv.GetPublicKeyX();
+  my_public_key.y = ppkv.GetPublicKeyY();
+
+  const auto [private_key, public_key] = GenerateECDHKeyPair();
+
+  pairing_handler->OnCommandView(BuilderToView(PairingPublicKeyBuilder::Create(public_key.x, public_key.y)));
+  // DHKey exchange finished
+  std::array<uint8_t, 32> dhkey = ComputeDHKey(private_key, my_public_key);
+
+  // Phasae 2 Stage 1 start
+  Octet16 ra, rb;
+  ra = rb = {0};
+
+  Octet16 Nb = PairingHandlerLe::GenerateRandom<16>();
+
+  // Compute confirm
+  Octet16 Cb = crypto_toolbox::f4((uint8_t*)my_public_key.x.data(), (uint8_t*)public_key.x.data(), Nb, 0);
+
+  pairing_handler->OnCommandView(BuilderToView(PairingConfirmBuilder::Create(Cb)));
+
+  // random
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(Code::PAIRING_RANDOM, outgoing_l2cap_packet_->GetCode());
+  auto prv = PairingRandomView::Create(outgoing_l2cap_packet_.value());
+  prv.IsValid();
+  Octet16 Na = prv.GetRandomValue();
+
+  // Compute Ca, compare
+  Octet16 Ca = crypto_toolbox::f4((uint8_t*)my_public_key.x.data(), (uint8_t*)public_key.x.data(), Na, 0);
+
+  EXPECT_EQ(Ca, Cb);
+
+  pairing_handler->OnCommandView(BuilderToView(PairingRandomBuilder::Create(Nb)));
+
+  // Start of authentication stage 2
+  uint8_t a[7];
+  uint8_t b[7];
+  memcpy(b, initial_informations.remote_connection_address.GetAddress().address, 6);
+  b[6] = (uint8_t)initial_informations.remote_connection_address.GetAddressType();
+  memcpy(a, initial_informations.my_connection_address.GetAddress().address, 6);
+  a[6] = (uint8_t)initial_informations.my_connection_address.GetAddressType();
+
+  Octet16 ltk, mac_key;
+  crypto_toolbox::f5(dhkey.data(), Na, Nb, a, b, &mac_key, &ltk);
+
+  PairingRequestView preqv = PairingRequestView::Create(pairing_request);
+  PairingResponseView prspv = PairingResponseView::Create(pairing_response);
+
+  preqv.IsValid();
+  prspv.IsValid();
+  std::array<uint8_t, 3> iocapA{static_cast<uint8_t>(preqv.GetIoCapability()),
+                                static_cast<uint8_t>(preqv.GetOobDataFlag()), preqv.GetAuthReq()};
+  std::array<uint8_t, 3> iocapB{static_cast<uint8_t>(prspv.GetIoCapability()),
+                                static_cast<uint8_t>(prspv.GetOobDataFlag()), prspv.GetAuthReq()};
+
+  Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b);
+  Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(Code::PAIRING_DH_KEY_CHECK, outgoing_l2cap_packet_->GetCode());
+  auto pdhkcv = PairingDhKeyCheckView::Create(outgoing_l2cap_packet_.value());
+  pdhkcv.IsValid();
+  EXPECT_EQ(pdhkcv.GetDhKeyCheck(), Ea);
+
+  pairing_handler->OnCommandView(BuilderToView(PairingDhKeyCheckBuilder::Create(Eb)));
+
+  // Phase 2 finished
+  // We don't care for the rest of the flow, let it die.
+}
+
+InitialInformations initial_informations_trsi{
+    .my_role = hci::Role::MASTER,
+    .my_connection_address = hci::AddressWithType(),
+
+    .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                              .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                              .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                              .maximum_encryption_key_size = 16,
+                              .initiator_key_distribution = 0x03,
+                              .responder_key_distribution = 0x03},
+
+    .remotely_initiated = true,
+    .remote_connection_address = hci::AddressWithType(),
+    .ui_handler = &uiMock,
+    .le_security_interface = &leSecurityMock,
+    .OnPairingFinished = OnPairingFinished,
+};
+
+/* This test verifies that when remote slave device sends security request , and user
+ * does accept the prompt, we do send pairing request */
+TEST_F(PairingHandlerUnitTest, test_remote_slave_initiating) {
+  initial_informations_trsi.proper_l2cap_interface = up_buffer_.get();
+  initial_informations_trsi.l2cap_handler = handler_;
+
+  std::unique_ptr<PairingHandlerLe> pairing_handler =
+      std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trsi);
+
+  // Simulate user accepting the pairing in UI
+  pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(Code::PAIRING_REQUEST, outgoing_l2cap_packet_->GetCode());
+
+  // We don't care for the rest of the flow, let it die.
+  pairing_handler.reset();
+}
+
+InitialInformations initial_informations_trmi{
+    .my_role = hci::Role::SLAVE,
+    .my_connection_address = hci::AddressWithType(),
+
+    .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                              .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                              .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                              .maximum_encryption_key_size = 16,
+                              .initiator_key_distribution = 0x03,
+                              .responder_key_distribution = 0x03},
+
+    .remotely_initiated = true,
+    .remote_connection_address = hci::AddressWithType(),
+    .pairing_request = PairingRequestView::Create(BuilderToView(
+        PairingRequestBuilder::Create(IoCapability::NO_INPUT_NO_OUTPUT, OobDataFlag::NOT_PRESENT,
+                                      AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03))),
+    .ui_handler = &uiMock,
+    .le_security_interface = &leSecurityMock,
+
+    .OnPairingFinished = OnPairingFinished,
+};
+
+/* This test verifies that when remote device sends pairing request, and user does accept the prompt, we do send proper
+ * reply back */
+TEST_F(PairingHandlerUnitTest, test_remote_master_initiating) {
+  initial_informations_trmi.proper_l2cap_interface = up_buffer_.get();
+  initial_informations_trmi.l2cap_handler = handler_;
+
+  std::unique_ptr<PairingHandlerLe> pairing_handler =
+      std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trmi);
+
+  // Simulate user accepting the pairing in UI
+  pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+  EXPECT_TRUE(WaitForOutgoingL2capPacket());
+  EXPECT_EQ(Code::PAIRING_RESPONSE, outgoing_l2cap_packet_->GetCode());
+  // Phase 1 finished.
+
+  // We don't care for the rest of the flow, it's handled in in other tests. let it die.
+  pairing_handler.reset();
+}
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/record/security_record.h b/gd/security/record/security_record.h
new file mode 100644
index 0000000..0c78113
--- /dev/null
+++ b/gd/security/record/security_record.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ *  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 <memory>
+
+#include "hci/device.h"
+
+namespace bluetooth {
+namespace security {
+namespace record {
+
+enum BondState { NOT_BONDED, PAIRING, BONDED };
+
+class SecurityRecord {
+ public:
+  SecurityRecord(std::shared_ptr<hci::Device> device) : device_(device), state_(NOT_BONDED) {}
+
+  /**
+   * Returns true if the device is bonded to another device
+   */
+  bool IsBonded() {
+    return state_ == BONDED;
+  }
+
+  /**
+   * Returns true if a device is currently pairing to another device
+   */
+  bool IsPairing() {
+    return state_ == PAIRING;
+  }
+
+  std::shared_ptr<hci::Device> GetDevice() {
+    return device_;
+  }
+
+ private:
+  const std::shared_ptr<hci::Device> device_;
+  BondState state_;
+};
+
+}  // namespace record
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/security_manager.cc b/gd/security/security_manager.cc
new file mode 100644
index 0000000..40858a9
--- /dev/null
+++ b/gd/security/security_manager.cc
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  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 "security_manager.h"
+
+#include "os/log.h"
+
+using namespace bluetooth::security;
+
+// Definition of Pure Virtual Destructor
+ISecurityManagerListener::~ISecurityManagerListener() {}
+
+void SecurityManager::Init() {
+  security_handler_->Post(
+      common::BindOnce(&internal::SecurityManagerImpl::Init, common::Unretained(security_manager_impl_)));
+}
+
+void SecurityManager::CreateBond(std::shared_ptr<hci::ClassicDevice> device) {
+  security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CreateBond,
+                                           common::Unretained(security_manager_impl_),
+                                           std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::CancelBond(std::shared_ptr<hci::ClassicDevice> device) {
+  security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CancelBond,
+                                           common::Unretained(security_manager_impl_),
+                                           std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) {
+  security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RemoveBond,
+                                           common::Unretained(security_manager_impl_),
+                                           std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler) {
+  security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RegisterCallbackListener,
+                                           common::Unretained(security_manager_impl_), listener, handler));
+}
+
+void SecurityManager::UnregisterCallbackListener(ISecurityManagerListener* listener) {
+  security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::UnregisterCallbackListener,
+                                           common::Unretained(security_manager_impl_), listener));
+}
diff --git a/gd/security/security_manager.h b/gd/security/security_manager.h
new file mode 100644
index 0000000..deb2788
--- /dev/null
+++ b/gd/security/security_manager.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ *  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 <memory>
+#include <vector>
+
+#include "hci/device.h"
+#include "hci/device_database.h"
+#include "security/internal/security_manager_impl.h"
+
+namespace bluetooth {
+namespace security {
+
+/**
+ * Callback interface from SecurityManager.
+ */
+class ISecurityManagerListener {
+ public:
+  virtual ~ISecurityManagerListener() = 0;
+
+  /**
+   * Called when a device is successfully bonded.
+   *
+   * @param device pointer to the bonded device
+   */
+  virtual void OnDeviceBonded(std::shared_ptr<bluetooth::hci::Device> device) = 0;
+
+  /**
+   * Called when a device is successfully un-bonded.
+   *
+   * @param device pointer to the device that is no longer bonded
+   */
+  virtual void OnDeviceUnbonded(std::shared_ptr<bluetooth::hci::Device> device) = 0;
+
+  /**
+   * Called as a result of a failure during the bonding process.
+   *
+   * @param device pointer to the device that is no longer bonded
+   */
+  virtual void OnDeviceBondFailed(std::shared_ptr<bluetooth::hci::Device> device) = 0;
+};
+
+/**
+ * Manages the security attributes, pairing, bonding of devices, and the
+ * encryption/decryption of communications.
+ */
+class SecurityManager {
+ public:
+  friend class SecurityModule;
+
+  /**
+   * Initialize the security record map from an internal device database.
+   */
+  void Init();
+
+  /**
+   * Checks the device for existing bond, if not bonded, initiates pairing.
+   *
+   * @param device pointer to device we want to bond with
+   */
+  void CreateBond(std::shared_ptr<hci::ClassicDevice> device);
+
+  /**
+   * Cancels the pairing process for this device.
+   *
+   * @param device pointer to device with which we want to cancel our bond
+   */
+  void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+  /**
+   * Disassociates the device and removes the persistent LTK
+   *
+   * @param device pointer to device we want to forget
+   */
+  void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+  /**
+   * Register to listen for callback events from SecurityManager
+   *
+   * @param listener ISecurityManagerListener instance to handle callbacks
+   */
+  void RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler);
+
+  /**
+   * Unregister listener for callback events from SecurityManager
+   *
+   * @param listener ISecurityManagerListener instance to unregister
+   */
+  void UnregisterCallbackListener(ISecurityManagerListener* listener);
+
+ protected:
+  SecurityManager(os::Handler* security_handler, internal::SecurityManagerImpl* security_manager_impl)
+      : security_handler_(security_handler), security_manager_impl_(security_manager_impl) {}
+
+ private:
+  os::Handler* security_handler_ = nullptr;
+  internal::SecurityManagerImpl* security_manager_impl_;
+  DISALLOW_COPY_AND_ASSIGN(SecurityManager);
+};
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/security_module.cc b/gd/security/security_module.cc
new file mode 100644
index 0000000..58b1f8c
--- /dev/null
+++ b/gd/security/security_module.cc
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "security"
+
+#include <memory>
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "hci/hci_layer.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "security/channel/security_manager_channel.h"
+#include "security/internal/security_manager_impl.h"
+#include "security/security_module.h"
+
+namespace bluetooth {
+namespace security {
+
+const ModuleFactory SecurityModule::Factory = ModuleFactory([]() { return new SecurityModule(); });
+
+struct SecurityModule::impl {
+  impl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module,
+       l2cap::classic::L2capClassicModule* l2cap_classic_module, hci::HciLayer* hci_layer)
+      : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module),
+        l2cap_classic_module_(l2cap_classic_module),
+        security_manager_channel_(new channel::SecurityManagerChannel(security_handler_, hci_layer)) {}
+
+  os::Handler* security_handler_;
+  l2cap::le::L2capLeModule* l2cap_le_module_;
+  l2cap::classic::L2capClassicModule* l2cap_classic_module_;
+  channel::SecurityManagerChannel* security_manager_channel_;
+  internal::SecurityManagerImpl security_manager_impl{security_handler_, l2cap_le_module_, l2cap_classic_module_,
+                                                      security_manager_channel_};
+};
+
+void SecurityModule::ListDependencies(ModuleList* list) {
+  list->add<l2cap::le::L2capLeModule>();
+  list->add<l2cap::classic::L2capClassicModule>();
+  list->add<hci::HciLayer>();
+}
+
+void SecurityModule::Start() {
+  pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<l2cap::le::L2capLeModule>(),
+                                  GetDependency<l2cap::classic::L2capClassicModule>(), GetDependency<hci::HciLayer>());
+}
+
+void SecurityModule::Stop() {
+  pimpl_.reset();
+}
+
+std::string SecurityModule::ToString() const {
+  return "Security Module";
+}
+
+std::unique_ptr<SecurityManager> SecurityModule::GetSecurityManager() {
+  return std::unique_ptr<SecurityManager>(
+      new SecurityManager(pimpl_->security_handler_, &pimpl_->security_manager_impl));
+}
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/l2cap_layer.h b/gd/security/security_module.h
similarity index 68%
copy from gd/l2cap/l2cap_layer.h
copy to gd/security/security_module.h
index 2e2aa60..2ec456d 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/security/security_module.h
@@ -17,16 +17,21 @@
 
 #include <memory>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
+#include "security/security_manager.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace security {
 
-class L2capLayer : public bluetooth::Module {
+class SecurityModule : public bluetooth::Module {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  SecurityModule() = default;
+  ~SecurityModule() = default;
+
+  /**
+   * Get the api to the SecurityManager
+   */
+  std::unique_ptr<SecurityManager> GetSecurityManager();
 
   static const ModuleFactory Factory;
 
@@ -37,16 +42,13 @@
 
   void Stop() override;
 
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
+  std::string ToString() const override;
 
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(SecurityModule);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/smp/smp_packets.pdl b/gd/security/smp_packets.pdl
similarity index 84%
rename from gd/smp/smp_packets.pdl
rename to gd/security/smp_packets.pdl
index f8cc84c..69269dd 100644
--- a/gd/smp/smp_packets.pdl
+++ b/gd/security/smp_packets.pdl
@@ -42,33 +42,14 @@
   BONDING = 1,
 }
 
-group AuthReq {
-  bonding_flags : BondingFlags,
-  mitm : 1, // Man-in-the-middle protection required
-  sc : 1, // Secure Connections
-  keypress : 1,  // Only used in Passkey Entry
-  ct2 : 1, // Support for the h7 function.
-  _reserved_ : 2,
-}
-
 group PairingInfo {
   io_capability : IoCapability,
   oob_data_flag : OobDataFlag,
-  AuthReq,
+  auth_req: 8,
   maximum_encryption_key_size : 5, // 7 - 16
   _reserved_ : 3,
-  // InitiatorKeyDistribution
-  initiator_enc_key : 1,
-  initiator_id_key : 1,
-  initiator_sign_key : 1,
-  initiator_link_key : 1,
-  _reserved_ : 4,
-  // ResponderKeyDistribution
-  responder_enc_key : 1,
-  responder_id_key : 1,
-  responder_sign_key : 1,
-  responder_link_key : 1,
-  _reserved_ : 4,
+  initiator_key_distribution : 8,
+  responder_key_distribution : 8,
 }
 
 packet PairingRequest : Command (code = PAIRING_REQUEST) {
@@ -114,7 +95,7 @@
 
 packet MasterIdentification : Command (code = MASTER_IDENTIFICATION) {
   ediv : 16,
-  rand : 64,
+  rand : 8[8],
 }
 
 packet IdentityInformation : Command (code = IDENTITY_INFORMATION) {
@@ -136,7 +117,7 @@
 }
 
 packet SecurityRequest : Command (code = SECURITY_REQUEST) {
-  AuthReq,
+  auth_req: 8,
 }
 
 packet PairingPublicKey : Command (code = PAIRING_PUBLIC_KEY) {
diff --git a/gd/security/test/fake_hci_layer.h b/gd/security/test/fake_hci_layer.h
new file mode 100644
index 0000000..84eff90
--- /dev/null
+++ b/gd/security/test/fake_hci_layer.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ *  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 "common/bind.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace security {
+
+using common::OnceCallback;
+using hci::CommandCompleteView;
+using hci::CommandPacketBuilder;
+using hci::CommandStatusView;
+using hci::EventCode;
+using hci::EventPacketBuilder;
+using hci::EventPacketView;
+using hci::HciLayer;
+using os::Handler;
+
+namespace {
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class CommandQueueEntry {
+ public:
+  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+                    OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler)
+      : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)),
+        caller_handler(handler) {}
+
+  CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+                    OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler)
+      : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)),
+        caller_handler(handler) {}
+
+  std::unique_ptr<CommandPacketBuilder> command;
+  bool waiting_for_status_;
+  OnceCallback<void(CommandStatusView)> on_status;
+  OnceCallback<void(CommandCompleteView)> on_complete;
+  Handler* caller_handler;
+};
+
+}  // namespace
+
+class FakeHciLayer : public HciLayer {
+ public:
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status,
+                      Handler* handler) override {
+    auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_status), handler);
+    command_queue_.push(std::move(command_queue_entry));
+  }
+
+  void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+                      OnceCallback<void(CommandCompleteView)> on_complete, Handler* handler) override {
+    auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_complete), handler);
+    command_queue_.push(std::move(command_queue_entry));
+  }
+
+  std::unique_ptr<CommandQueueEntry> GetLastCommand() {
+    EXPECT_FALSE(command_queue_.empty());
+    auto last = std::move(command_queue_.front());
+    command_queue_.pop();
+    return last;
+  }
+
+  void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+                            Handler* handler) override {
+    registered_events_[event_code] = event_handler;
+  }
+
+  void UnregisterEventHandler(EventCode event_code) override {
+    registered_events_.erase(event_code);
+  }
+
+  void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+    auto packet = GetPacketView(std::move(event_builder));
+    EventPacketView event = EventPacketView::Create(packet);
+    ASSERT_TRUE(event.IsValid());
+    EventCode event_code = event.GetEventCode();
+    EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end());
+    registered_events_[event_code].Run(event);
+  }
+
+  void ListDependencies(ModuleList* list) override {}
+  void Start() override {}
+  void Stop() override {}
+
+ private:
+  std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+  std::queue<std::unique_ptr<CommandQueueEntry>> command_queue_;
+};
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/test/fake_l2cap_test.cc b/gd/security/test/fake_l2cap_test.cc
new file mode 100644
index 0000000..2d885e7
--- /dev/null
+++ b/gd/security/test/fake_l2cap_test.cc
@@ -0,0 +1,131 @@
+/******************************************************************************
+ *
+ *  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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "hci/le_security_interface.h"
+#include "packet/raw_builder.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+using testing::Matcher;
+using testing::SaveArg;
+
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EncryptionChangeBuilder;
+using bluetooth::hci::EncryptionEnabled;
+using bluetooth::hci::ErrorCode;
+using bluetooth::hci::EventPacketBuilder;
+using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeSecurityCommandBuilder;
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+
+template <class T>
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<T> packet) {
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+  std::promise<void> promise;
+  auto future = promise.get_future();
+  handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+  auto status = future.wait_for(std::chrono::milliseconds(3));
+  EXPECT_EQ(status, std::future_status::ready);
+}
+}  // namespace
+
+class FakeL2capTest : public testing::Test {
+ protected:
+  void SetUp() {}
+
+  void TearDown() {}
+
+ public:
+};
+
+void my_enqueue_callback() {
+  LOG_INFO("packet ready for dequeue!");
+}
+
+/* This test verifies that Just Works pairing flow works.
+ * Both simulated devices specify capabilities as NO_INPUT_NO_OUTPUT, and secure connecitons support */
+TEST_F(FakeL2capTest, test_bidi_queue_example) {
+  os::Thread* thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+  os::Handler* handler_ = new os::Handler(thread_);
+
+  common::BidiQueue<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>> bidi_queue{10};
+
+  os::EnqueueBuffer<packet::BasePacketBuilder> enqueue_buffer{bidi_queue.GetDownEnd()};
+
+  // This is test packet we are sending down the queue to the other end;
+  auto test_packet = EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, 0x0020, EncryptionEnabled::ON);
+
+  // send the packet through the queue
+  enqueue_buffer.Enqueue(std::move(test_packet), handler_);
+
+  // give queue some time to push the packet through
+  sync_handler(handler_);
+
+  // packet is through the queue, receive it on the other end.
+  auto test_packet_from_other_end = bidi_queue.GetUpEnd()->TryDequeue();
+
+  EXPECT_TRUE(test_packet_from_other_end != nullptr);
+
+  // This is how we receive data
+  os::EnqueueBuffer<packet::PacketView<packet::kLittleEndian>> up_end_enqueue_buffer{bidi_queue.GetUpEnd()};
+  bidi_queue.GetDownEnd()->RegisterDequeue(handler_, common::Bind(&my_enqueue_callback));
+
+  auto packet_one = std::make_unique<packet::RawBuilder>();
+  packet_one->AddOctets({1, 2, 3});
+
+  up_end_enqueue_buffer.Enqueue(std::make_unique<PacketView<kLittleEndian>>(GetPacketView(std::move(packet_one))),
+                                handler_);
+
+  sync_handler(handler_);
+
+  auto other_end_packet = bidi_queue.GetDownEnd()->TryDequeue();
+  EXPECT_TRUE(other_end_packet != nullptr);
+
+  bidi_queue.GetDownEnd()->UnregisterDequeue();
+  handler_->Clear();
+  delete handler_;
+  delete thread_;
+}
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/test/mocks.h b/gd/security/test/mocks.h
new file mode 100644
index 0000000..812c9a1
--- /dev/null
+++ b/gd/security/test/mocks.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *  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 <gmock/gmock.h>
+
+#include "hci/address.h"
+#include "hci/le_security_interface.h"
+#include "security/ui.h"
+
+namespace bluetooth {
+namespace security {
+
+class UIMock : public UI {
+ public:
+  UIMock() {}
+  ~UIMock() override = default;
+
+  MOCK_METHOD2(DisplayPairingPrompt, void(const bluetooth::hci::AddressWithType&, std::string&));
+  MOCK_METHOD1(CancelPairingPrompt, void(const bluetooth::hci::AddressWithType&));
+  MOCK_METHOD1(DisplayConfirmValue, void(uint32_t));
+  MOCK_METHOD0(DisplayEnterPasskeyDialog, void());
+  MOCK_METHOD1(DisplayPasskey, void(uint32_t));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UIMock);
+};
+
+class LeSecurityInterfaceMock : public hci::LeSecurityInterface {
+ public:
+  MOCK_METHOD3(EnqueueCommand,
+               void(std::unique_ptr<hci::LeSecurityCommandBuilder> command,
+                    common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler));
+  MOCK_METHOD3(EnqueueCommand,
+               void(std::unique_ptr<hci::LeSecurityCommandBuilder> command,
+                    common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler));
+};
+
+}  // namespace security
+}  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/test/pairing_handler_le_pair_test.cc b/gd/security/test/pairing_handler_le_pair_test.cc
new file mode 100644
index 0000000..1bed89c
--- /dev/null
+++ b/gd/security/test/pairing_handler_le_pair_test.cc
@@ -0,0 +1,638 @@
+/******************************************************************************
+ *
+ *  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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "common/testing/wired_pair_of_bidi_queues.h"
+#include "hci/le_security_interface.h"
+#include "packet/raw_builder.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+using testing::Matcher;
+using testing::SaveArg;
+
+using bluetooth::hci::Address;
+using bluetooth::hci::AddressType;
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EncryptionChangeBuilder;
+using bluetooth::hci::EncryptionEnabled;
+using bluetooth::hci::ErrorCode;
+using bluetooth::hci::EventPacketBuilder;
+using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeSecurityCommandBuilder;
+
+// run:
+// out/host/linux-x86/nativetest/bluetooth_test_gd/bluetooth_test_gd --gtest_filter=Pairing*
+// adb shell /data/nativetest/bluetooth_test_gd/bluetooth_test_gd  --gtest_filter=PairingHandlerPairTest.*
+// --gtest_repeat=10 --gtest_shuffle
+
+namespace bluetooth {
+namespace security {
+CommandView CommandBuilderToView(std::unique_ptr<BasePacketBuilder> builder) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  builder->Serialize(it);
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+  return CommandView::Create(temp_cmd_view);
+}
+
+EventPacketView EventBuilderToView(std::unique_ptr<EventPacketBuilder> builder) {
+  std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+  BitInserter it(*packet_bytes);
+  builder->Serialize(it);
+  PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+  auto temp_evt_view = EventPacketView::Create(packet_bytes_view);
+  return EventPacketView::Create(temp_evt_view);
+}
+}  // namespace security
+}  // namespace bluetooth
+
+namespace {
+
+constexpr uint16_t CONN_HANDLE_MASTER = 0x31, CONN_HANDLE_SLAVE = 0x32;
+std::unique_ptr<bluetooth::security::PairingHandlerLe> pairing_handler_a, pairing_handler_b;
+
+}  // namespace
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+Address ADDRESS_MASTER{{0x26, 0x64, 0x76, 0x86, 0xab, 0xba}};
+AddressType ADDRESS_TYPE_MASTER = AddressType::RANDOM_DEVICE_ADDRESS;
+
+Address ADDRESS_SLAVE{{0x33, 0x58, 0x24, 0x76, 0x11, 0x89}};
+AddressType ADDRESS_TYPE_SLAVE = AddressType::RANDOM_DEVICE_ADDRESS;
+
+std::optional<PairingResultOrFailure> pairing_result_master;
+std::optional<PairingResultOrFailure> pairing_result_slave;
+
+void OnPairingFinishedMaster(PairingResultOrFailure r) {
+  pairing_result_master = r;
+  if (std::holds_alternative<PairingResult>(r)) {
+    LOG_INFO("pairing finished successfully with %s", std::get<PairingResult>(r).connection_address.ToString().c_str());
+  } else {
+    LOG_INFO("pairing with ... failed: %s", std::get<PairingFailure>(r).message.c_str());
+  }
+}
+
+void OnPairingFinishedSlave(PairingResultOrFailure r) {
+  pairing_result_slave = r;
+  if (std::holds_alternative<PairingResult>(r)) {
+    LOG_INFO("pairing finished successfully with %s", std::get<PairingResult>(r).connection_address.ToString().c_str());
+  } else {
+    LOG_INFO("pairing with ... failed: %s", std::get<PairingFailure>(r).message.c_str());
+  }
+}
+
+};  // namespace
+
+// We obtain this mutex when we start initializing the handlers, and relese it when both handlers are initialized
+std::mutex handlers_initialization_guard;
+
+class PairingHandlerPairTest : public testing::Test {
+  void dequeue_callback_master() {
+    auto packet_bytes_view = l2cap_->GetQueueAUpEnd()->TryDequeue();
+    if (!packet_bytes_view) LOG_ERROR("Received dequeue, but no data ready...");
+
+    auto temp_cmd_view = CommandView::Create(*packet_bytes_view);
+    if (!first_command_sent) {
+      first_command = std::make_unique<CommandView>(CommandView::Create(temp_cmd_view));
+      first_command_sent = true;
+      return;
+    }
+
+    if (!pairing_handler_a) LOG_ALWAYS_FATAL("Slave handler not initlized yet!");
+
+    pairing_handler_a->OnCommandView(CommandView::Create(temp_cmd_view));
+  }
+
+  void dequeue_callback_slave() {
+    auto packet_bytes_view = l2cap_->GetQueueBUpEnd()->TryDequeue();
+    if (!packet_bytes_view) LOG_ERROR("Received dequeue, but no data ready...");
+
+    auto temp_cmd_view = CommandView::Create(*packet_bytes_view);
+    if (!first_command_sent) {
+      first_command = std::make_unique<CommandView>(CommandView::Create(temp_cmd_view));
+      first_command_sent = true;
+      return;
+    }
+
+    if (!pairing_handler_b) LOG_ALWAYS_FATAL("Master handler not initlized yet!");
+
+    pairing_handler_b->OnCommandView(CommandView::Create(temp_cmd_view));
+  }
+
+ protected:
+  void SetUp() {
+    thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+    handler_ = new os::Handler(thread_);
+
+    l2cap_ = new common::testing::WiredPairOfL2capQueues(handler_);
+    // master sends it's packet into l2cap->down_buffer_b_
+    // slave sends it's packet into l2cap->down_buffer_a_
+    l2cap_->GetQueueAUpEnd()->RegisterDequeue(
+        handler_, common::Bind(&PairingHandlerPairTest::dequeue_callback_master, common::Unretained(this)));
+    l2cap_->GetQueueBUpEnd()->RegisterDequeue(
+        handler_, common::Bind(&PairingHandlerPairTest::dequeue_callback_slave, common::Unretained(this)));
+
+    up_buffer_a_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(l2cap_->GetQueueAUpEnd());
+    up_buffer_b_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(l2cap_->GetQueueBUpEnd());
+
+    master_setup = {
+        .my_role = hci::Role::MASTER,
+        .my_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+
+        .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                                  .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                                  .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                                  .maximum_encryption_key_size = 16,
+                                  .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+                                  .responder_key_distribution = KeyMaskId | KeyMaskSign},
+
+        .remotely_initiated = false,
+        .connection_handle = CONN_HANDLE_MASTER,
+        .remote_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+        .ui_handler = &master_ui_handler,
+        .le_security_interface = &master_le_security_mock,
+        .proper_l2cap_interface = up_buffer_a_.get(),
+        .l2cap_handler = handler_,
+        .OnPairingFinished = OnPairingFinishedMaster,
+    };
+
+    slave_setup = {
+        .my_role = hci::Role::SLAVE,
+
+        .my_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+        .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                                  .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                                  .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                                  .maximum_encryption_key_size = 16,
+                                  .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+                                  .responder_key_distribution = KeyMaskId | KeyMaskSign},
+        .remotely_initiated = true,
+        .connection_handle = CONN_HANDLE_SLAVE,
+        .remote_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+        .ui_handler = &slave_ui_handler,
+        .le_security_interface = &slave_le_security_mock,
+        .proper_l2cap_interface = up_buffer_b_.get(),
+        .l2cap_handler = handler_,
+        .OnPairingFinished = OnPairingFinishedSlave,
+    };
+
+    RecordSuccessfulEncryptionComplete();
+  }
+
+  void TearDown() {
+    ::testing::Mock::VerifyAndClearExpectations(&slave_ui_handler);
+    ::testing::Mock::VerifyAndClearExpectations(&master_ui_handler);
+    ::testing::Mock::VerifyAndClearExpectations(&slave_le_security_mock);
+    ::testing::Mock::VerifyAndClearExpectations(&master_le_security_mock);
+
+    pairing_handler_a.reset();
+    pairing_handler_b.reset();
+    pairing_result_master.reset();
+    pairing_result_slave.reset();
+
+    first_command_sent = false;
+    first_command.reset();
+
+    l2cap_->GetQueueAUpEnd()->UnregisterDequeue();
+    l2cap_->GetQueueBUpEnd()->UnregisterDequeue();
+
+    delete l2cap_;
+    handler_->Clear();
+    delete handler_;
+    delete thread_;
+  }
+
+  void RecordPairingPromptHandling(UIMock& ui_mock, std::unique_ptr<PairingHandlerLe>* handler) {
+    EXPECT_CALL(ui_mock, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([handler]() {
+      LOG_INFO("UI mock received pairing prompt");
+
+      {
+        // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+        std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+      }
+
+      if (!(*handler)) LOG_ALWAYS_FATAL("handler not initalized yet!");
+      // Simulate user accepting the pairing in UI
+      (*handler)->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+    }));
+  }
+
+  void RecordSuccessfulEncryptionComplete() {
+    // For now, all tests are succeeding to go through Encryption. Record that in the setup.
+    //  Once we test failure cases, move this to each test
+    EXPECT_CALL(master_le_security_mock,
+                EnqueueCommand(_, Matcher<common::OnceCallback<void(CommandStatusView)>>(_), _))
+        .Times(1)
+        .WillOnce([](std::unique_ptr<LeSecurityCommandBuilder> command,
+                     common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) {
+          // TODO: on_status.Run();
+
+          pairing_handler_a->OnHciEvent(EventBuilderToView(
+              EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, CONN_HANDLE_MASTER, EncryptionEnabled::ON)));
+
+          pairing_handler_b->OnHciEvent(EventBuilderToView(
+              EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, CONN_HANDLE_SLAVE, EncryptionEnabled::ON)));
+        });
+  }
+
+ public:
+  std::unique_ptr<bluetooth::security::CommandView> WaitFirstL2capCommand() {
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+
+    return std::move(first_command);
+  }
+
+  InitialInformations master_setup;
+  InitialInformations slave_setup;
+  UIMock master_ui_handler;
+  UIMock slave_ui_handler;
+  LeSecurityInterfaceMock master_le_security_mock;
+  LeSecurityInterfaceMock slave_le_security_mock;
+
+  uint16_t first_command_sent = false;
+  std::unique_ptr<bluetooth::security::CommandView> first_command;
+
+  os::Thread* thread_;
+  os::Handler* handler_;
+  common::testing::WiredPairOfL2capQueues* l2cap_;
+
+  std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_a_;
+  std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_b_;
+};
+
+/* This test verifies that Just Works pairing flow works.
+ * Both simulated devices specify capabilities as NO_INPUT_NO_OUTPUT, and secure connecitons support */
+TEST_F(PairingHandlerPairTest, test_secure_connections_just_works) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+    auto first_pkt = WaitFirstL2capCommand();
+    slave_setup.pairing_request = PairingRequestView::Create(*first_pkt);
+
+    EXPECT_CALL(slave_ui_handler, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([] {
+      LOG_INFO("UI mock received pairing prompt");
+
+      {
+        // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+        std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+      }
+
+      if (!pairing_handler_b) LOG_ALWAYS_FATAL("handler not initalized yet!");
+
+      // Simulate user accepting the pairing in UI
+      pairing_handler_b->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+    }));
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_just_works_slave_initiated) {
+  master_setup = {
+      .my_role = hci::Role::MASTER,
+      .my_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+      .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                                .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                                .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                                .maximum_encryption_key_size = 16,
+                                .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+                                .responder_key_distribution = KeyMaskId | KeyMaskSign},
+      .remotely_initiated = true,
+      .connection_handle = CONN_HANDLE_MASTER,
+      .remote_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+      .ui_handler = &master_ui_handler,
+      .le_security_interface = &master_le_security_mock,
+      .proper_l2cap_interface = up_buffer_a_.get(),
+      .l2cap_handler = handler_,
+      .OnPairingFinished = OnPairingFinishedMaster,
+  };
+
+  slave_setup = {
+      .my_role = hci::Role::SLAVE,
+      .my_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+      .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+                                .oob_data_flag = OobDataFlag::NOT_PRESENT,
+                                .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+                                .maximum_encryption_key_size = 16,
+                                .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+                                .responder_key_distribution = KeyMaskId | KeyMaskSign},
+      .remotely_initiated = false,
+      .connection_handle = CONN_HANDLE_SLAVE,
+      .remote_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+      .ui_handler = &slave_ui_handler,
+      .le_security_interface = &slave_le_security_mock,
+      .proper_l2cap_interface = up_buffer_b_.get(),
+      .l2cap_handler = handler_,
+      .OnPairingFinished = OnPairingFinishedSlave,
+  };
+
+  std::unique_ptr<bluetooth::security::CommandView> first_pkt;
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+
+    first_pkt = WaitFirstL2capCommand();
+
+    EXPECT_CALL(master_ui_handler, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([&first_pkt, this] {
+      LOG_INFO("UI mock received pairing prompt");
+
+      {
+        // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+        std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+      }
+      if (!pairing_handler_a) LOG_ALWAYS_FATAL("handler not initalized yet!");
+      // Simulate user accepting the pairing in UI
+      pairing_handler_a->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+      // Send the first packet from the slave to master
+      auto view_to_packet = std::make_unique<packet::RawBuilder>();
+      view_to_packet->AddOctets(std::vector(first_pkt->begin(), first_pkt->end()));
+      up_buffer_b_->Enqueue(std::move(view_to_packet), handler_);
+    }));
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+  }
+
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_numeric_comparison) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_YES_NO;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_YES_NO;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+  uint32_t num_value_slave = 0;
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    // Initiator must be initialized after the responder.
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    EXPECT_CALL(slave_ui_handler, DisplayConfirmValue(_)).WillOnce(SaveArg<0>(&num_value_slave));
+    EXPECT_CALL(master_ui_handler, DisplayConfirmValue(_)).WillOnce(Invoke([&](uint32_t num_value) {
+      EXPECT_EQ(num_value_slave, num_value);
+      if (num_value_slave == num_value) {
+        pairing_handler_a->OnUiAction(PairingEvent::CONFIRM_YESNO, 0x01);
+        pairing_handler_b->OnUiAction(PairingEvent::CONFIRM_YESNO, 0x01);
+      }
+    }));
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_passkey_entry) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+  uint32_t passkey = std::numeric_limits<uint32_t>::max();
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    EXPECT_CALL(slave_ui_handler, DisplayPasskey(_)).WillOnce(SaveArg<0>(&passkey));
+    EXPECT_CALL(master_ui_handler, DisplayEnterPasskeyDialog()).WillOnce(Invoke([&]() {
+      LOG_INFO("Passkey prompt displayed entering passkey: %08x", passkey);
+      std::this_thread::sleep_for(1ms);
+
+      // handle case where prompts are displayed in different order in the test!
+      if (passkey == std::numeric_limits<uint32_t>::max()) FAIL();
+
+      pairing_handler_a->OnUiAction(PairingEvent::PASSKEY, passkey);
+    }));
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  // Initiator must be initialized after the responder.
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_out_of_band) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+  master_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+  slave_setup.remote_oob_data =
+      std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+          .le_sc_c = master_setup.my_oob_data->c,
+          .le_sc_r = master_setup.my_oob_data->r,
+      });
+
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_out_of_band_two_way) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+  master_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+  slave_setup.remote_oob_data =
+      std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+          .le_sc_c = master_setup.my_oob_data->c,
+          .le_sc_r = master_setup.my_oob_data->r,
+      });
+
+  slave_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+  master_setup.remote_oob_data =
+      std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+          .le_sc_c = slave_setup.my_oob_data->c,
+          .le_sc_r = slave_setup.my_oob_data->r,
+      });
+
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_legacy_just_works) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm,
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm;
+
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_legacy_passkey_entry) {
+  master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_DISPLAY;
+  master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm,
+
+  slave_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+  slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+  slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm;
+
+  {
+    std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+    pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+    while (!first_command_sent) {
+      std::this_thread::sleep_for(1ms);
+      LOG_INFO("waiting for first command...");
+    }
+    slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+    RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+    EXPECT_CALL(slave_ui_handler, DisplayEnterPasskeyDialog());
+    EXPECT_CALL(master_ui_handler, DisplayConfirmValue(_)).WillOnce(Invoke([&](uint32_t passkey) {
+      LOG_INFO("Passkey prompt displayed entering passkey: %08x", passkey);
+      std::this_thread::sleep_for(1ms);
+
+      // TODO: handle case where prompts are displayed in different order in the test!
+      pairing_handler_b->OnUiAction(PairingEvent::PASSKEY, passkey);
+    }));
+
+    pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+  }
+  pairing_handler_a->WaitUntilPairingFinished();
+  pairing_handler_b->WaitUntilPairingFinished();
+
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+  EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+}  // namespace security
+}  // namespace bluetooth
diff --git a/gd/security/ui.h b/gd/security/ui.h
new file mode 100644
index 0000000..83041de
--- /dev/null
+++ b/gd/security/ui.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ *  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 "hci/address_with_type.h"
+
+// Through this interface we talk to the user, asking for confirmations/acceptance.
+class UI {
+ public:
+  virtual ~UI(){};
+
+  /* Remote device tries to initiate pairing, ask user to confirm */
+  virtual void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& address, std::string& name) = 0;
+
+  /* Remove the pairing prompt from DisplayPairingPrompt, i.e. remote device disconnected, or some application requested
+   * bond with this device */
+  virtual void CancelPairingPrompt(const bluetooth::hci::AddressWithType& address) = 0;
+
+  /* Display value for Comprision */
+  virtual void DisplayConfirmValue(uint32_t numeric_value) = 0;
+
+  /* Display a dialog box that will let user enter the Passkey */
+  virtual void DisplayEnterPasskeyDialog() = 0;
+
+  /* Present the passkey value to the user */
+  virtual void DisplayPasskey(uint32_t passkey) = 0;
+};
+
+/* Through this interface, UI provides us with user choices. */
+class UICallbacks {
+ public:
+  virtual ~UICallbacks() = 0;
+
+  /* User accepted pairing prompt */
+  virtual void OnPairingPromptAccepted(const bluetooth::hci::Address& address) = 0;
+
+  /* User confirmed that displayed value matches the value on the other device */
+  virtual void OnConfirmYesNo(const bluetooth::hci::Address& address, bool conformed) = 0;
+
+  /* User typed the value displayed on the other device. This is either Passkey or the Confirm value */
+  virtual void OnPasskeyEntry(const bluetooth::hci::Address& address, uint32_t passkey) = 0;
+};
diff --git a/gd/shim/Android.bp b/gd/shim/Android.bp
new file mode 100644
index 0000000..33c9b65
--- /dev/null
+++ b/gd/shim/Android.bp
@@ -0,0 +1,24 @@
+filegroup {
+    name: "BluetoothShimSources",
+    srcs: [
+            "advertising.cc",
+            "controller.cc",
+            "connectability.cc",
+            "discoverability.cc",
+            "hci_layer.cc",
+            "inquiry.cc",
+            "l2cap.cc",
+            "name.cc",
+            "page.cc",
+            "scanning.cc",
+            "stack.cc",
+    ],
+}
+
+filegroup {
+    name: "BluetoothShimTestSources",
+    srcs: [
+    ],
+}
+
+
diff --git a/gd/shim/advertising.cc b/gd/shim/advertising.cc
new file mode 100644
index 0000000..b7e0b4e
--- /dev/null
+++ b/gd/shim/advertising.cc
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "hci/le_advertising_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/advertising.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Advertising::impl {
+  hci::LeAdvertisingManager* module_{nullptr};
+
+  impl(hci::LeAdvertisingManager* module);
+  ~impl();
+};
+
+const ModuleFactory Advertising::Factory = ModuleFactory([]() { return new Advertising(); });
+
+Advertising::impl::impl(hci::LeAdvertisingManager* advertising_manager) : module_(advertising_manager) {}
+
+Advertising::impl::~impl() {}
+
+/**
+ * Module methods
+ */
+void Advertising::ListDependencies(ModuleList* list) {
+  list->add<hci::LeAdvertisingManager>();
+}
+
+void Advertising::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<hci::LeAdvertisingManager>());
+}
+
+void Advertising::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.h b/gd/shim/advertising.h
similarity index 61%
copy from gd/l2cap/l2cap_layer.h
copy to gd/shim/advertising.h
index 2e2aa60..17c094a 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/shim/advertising.h
@@ -16,37 +16,31 @@
 #pragma once
 
 #include <memory>
+#include <string>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
+#include "shim/iadvertising.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-class L2capLayer : public bluetooth::Module {
+class Advertising : public bluetooth::Module, public bluetooth::shim::IAdvertising {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  Advertising() = default;
+  ~Advertising() = default;
 
   static const ModuleFactory Factory;
 
  protected:
-  void ListDependencies(ModuleList* list) override;
-
-  void Start() override;
-
-  void Stop() override;
-
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
 
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Advertising);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/connectability.cc b/gd/shim/connectability.cc
new file mode 100644
index 0000000..2b779fd
--- /dev/null
+++ b/gd/shim/connectability.cc
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/connectability.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/connectability.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Connectability::Factory = ModuleFactory([]() { return new Connectability(); });
+
+struct Connectability::impl {
+  impl(neighbor::ConnectabilityModule* module) : module_(module) {}
+
+  neighbor::ConnectabilityModule* module_{nullptr};
+};
+
+void Connectability::StartConnectability() {
+  pimpl_->module_->StartConnectability();
+}
+
+void Connectability::StopConnectability() {
+  pimpl_->module_->StopConnectability();
+}
+
+bool Connectability::IsConnectable() const {
+  return pimpl_->module_->IsConnectable();
+}
+
+/**
+ * Module methods
+ */
+void Connectability::ListDependencies(ModuleList* list) {
+  list->add<neighbor::ConnectabilityModule>();
+}
+
+void Connectability::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<neighbor::ConnectabilityModule>());
+}
+
+void Connectability::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/connectability.h b/gd/shim/connectability.h
new file mode 100644
index 0000000..780b5be
--- /dev/null
+++ b/gd/shim/connectability.h
@@ -0,0 +1,49 @@
+/*
+ * 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 <memory>
+
+#include "module.h"
+#include "shim/iconnectability.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Connectability : public bluetooth::Module, public bluetooth::shim::IConnectability {
+ public:
+  void StartConnectability() override;
+  void StopConnectability() override;
+  bool IsConnectable() const override;
+
+  Connectability() = default;
+  ~Connectability() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Connectability);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/controller.cc b/gd/shim/controller.cc
new file mode 100644
index 0000000..6b82bb6
--- /dev/null
+++ b/gd/shim/controller.cc
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/controller.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); });
+
+struct Controller::impl {
+  impl(hci::Controller* hci_controller) : hci_controller_(hci_controller) {}
+
+  hci::Controller* hci_controller_{nullptr};
+};
+
+bool Controller::IsCommandSupported(int op_code) const {
+  return pimpl_->hci_controller_->IsSupported((bluetooth::hci::OpCode)op_code);
+}
+
+uint16_t Controller::GetControllerAclPacketLength() const {
+  return pimpl_->hci_controller_->GetControllerAclPacketLength();
+}
+
+LeBufferSize Controller::GetControllerLeBufferSize() const {
+  LeBufferSize le_buffer_size;
+  hci::LeBufferSize hci_le_buffer_size = pimpl_->hci_controller_->GetControllerLeBufferSize();
+
+  le_buffer_size.le_data_packet_length = hci_le_buffer_size.le_data_packet_length_;
+  le_buffer_size.total_num_le_packets = hci_le_buffer_size.total_num_le_packets_;
+  return le_buffer_size;
+}
+
+LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() const {
+  LeMaximumDataLength maximum_data_length;
+  hci::LeMaximumDataLength hci_maximum_data_length = pimpl_->hci_controller_->GetControllerLeMaximumDataLength();
+
+  maximum_data_length.supported_max_tx_octets = hci_maximum_data_length.supported_max_tx_octets_;
+  maximum_data_length.supported_max_tx_time = hci_maximum_data_length.supported_max_tx_time_;
+  maximum_data_length.supported_max_rx_octets = hci_maximum_data_length.supported_max_rx_octets_;
+  maximum_data_length.supported_max_rx_time = hci_maximum_data_length.supported_max_rx_time_;
+  return maximum_data_length;
+}
+
+uint16_t Controller::GetControllerNumAclPacketBuffers() const {
+  return pimpl_->hci_controller_->GetControllerNumAclPacketBuffers();
+}
+
+uint64_t Controller::GetControllerLeLocalSupportedFeatures() const {
+  return pimpl_->hci_controller_->GetControllerLeLocalSupportedFeatures();
+}
+
+uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) const {
+  return pimpl_->hci_controller_->GetControllerLocalExtendedFeatures(page_number);
+}
+
+std::string Controller::GetControllerMacAddress() const {
+  return pimpl_->hci_controller_->GetControllerMacAddress().ToString();
+}
+
+uint64_t Controller::GetControllerLeSupportedStates() const {
+  return pimpl_->hci_controller_->GetControllerLeSupportedStates();
+}
+
+uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() const {
+  return pimpl_->hci_controller_->GetControllerLocalExtendedFeaturesMaxPageNumber();
+}
+
+/**
+ * Module methods
+ */
+void Controller::ListDependencies(ModuleList* list) {
+  list->add<hci::Controller>();
+}
+
+void Controller::Start() {
+  LOG_INFO("%s Starting controller shim layer", __func__);
+  pimpl_ = std::make_unique<impl>(GetDependency<hci::Controller>());
+}
+
+void Controller::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/controller.h b/gd/shim/controller.h
new file mode 100644
index 0000000..39bd440
--- /dev/null
+++ b/gd/shim/controller.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/icontroller.h"
+
+/**
+ * Gd shim controller module that depends upon the Gd controller module.
+ *
+ * Wraps the Gd controller module to expose a sufficient API to allow
+ * proper operation of the legacy shim controller interface.
+ *
+ */
+namespace bluetooth {
+namespace shim {
+
+class Controller : public bluetooth::Module, public bluetooth::shim::IController {
+ public:
+  Controller() = default;
+  ~Controller() = default;
+
+  static const ModuleFactory Factory;
+
+  // Exported controller methods from IController for shim layer
+  bool IsCommandSupported(int op_code) const override;
+  LeBufferSize GetControllerLeBufferSize() const override;
+  LeMaximumDataLength GetControllerLeMaximumDataLength() const override;
+  std::string GetControllerMacAddress() const override;
+  uint16_t GetControllerAclPacketLength() const override;
+  uint16_t GetControllerNumAclPacketBuffers() const override;
+  uint64_t GetControllerLeLocalSupportedFeatures() const override;
+  uint64_t GetControllerLeSupportedStates() const override;
+  uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const override;
+  uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const override;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Controller);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/discoverability.cc b/gd/shim/discoverability.cc
new file mode 100644
index 0000000..5754882
--- /dev/null
+++ b/gd/shim/discoverability.cc
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/discoverability.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/discoverability.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Discoverability::Factory = ModuleFactory([]() { return new Discoverability(); });
+
+struct Discoverability::impl {
+  impl(neighbor::DiscoverabilityModule* module) : module_(module) {}
+
+  neighbor::DiscoverabilityModule* module_{nullptr};
+};
+
+void Discoverability::StopDiscoverability() {
+  return pimpl_->module_->StopDiscoverability();
+}
+
+void Discoverability::StartLimitedDiscoverability() {
+  return pimpl_->module_->StartLimitedDiscoverability();
+}
+
+void Discoverability::StartGeneralDiscoverability() {
+  return pimpl_->module_->StartGeneralDiscoverability();
+}
+
+bool Discoverability::IsGeneralDiscoverabilityEnabled() const {
+  return pimpl_->module_->IsGeneralDiscoverabilityEnabled();
+}
+
+bool Discoverability::IsLimitedDiscoverabilityEnabled() const {
+  return pimpl_->module_->IsLimitedDiscoverabilityEnabled();
+}
+
+/**
+ * Module methods
+ */
+void Discoverability::ListDependencies(ModuleList* list) {
+  list->add<neighbor::DiscoverabilityModule>();
+}
+
+void Discoverability::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<neighbor::DiscoverabilityModule>());
+}
+
+void Discoverability::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/discoverability.h b/gd/shim/discoverability.h
new file mode 100644
index 0000000..34ad49a
--- /dev/null
+++ b/gd/shim/discoverability.h
@@ -0,0 +1,52 @@
+/*
+ * 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 <memory>
+
+#include "module.h"
+#include "shim/idiscoverability.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Discoverability : public bluetooth::Module, public bluetooth::shim::IDiscoverability {
+ public:
+  void StartGeneralDiscoverability() override;
+  void StartLimitedDiscoverability() override;
+  void StopDiscoverability() override;
+
+  bool IsGeneralDiscoverabilityEnabled() const override;
+  bool IsLimitedDiscoverabilityEnabled() const override;
+
+  Discoverability() = default;
+  ~Discoverability() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Discoverability);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/hci_layer.cc b/gd/shim/hci_layer.cc
new file mode 100644
index 0000000..e11454b
--- /dev/null
+++ b/gd/shim/hci_layer.cc
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <cstdint>
+#include <memory>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+#include "shim/hci_layer.h"
+
+namespace bluetooth {
+namespace shim {
+
+using TokenQueue = std::queue<const void*>;
+using OpCodeTokenQueueMap = std::unordered_map<hci::OpCode, TokenQueue>;
+
+const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
+
+struct HciLayer::impl {
+  impl(os::Handler* handler, hci::HciLayer* hci_layer) : handler_(handler), hci_layer_(hci_layer) {}
+
+  void OnTransmitPacketCommandComplete(hci::CommandCompleteView view) {
+    if (command_complete_callback_ == nullptr) {
+      LOG_WARN("%s Received packet complete with no complete callback registered", __func__);
+      return;
+    }
+
+    uint16_t command_op_code = static_cast<uint16_t>(view.GetCommandOpCode());
+    std::vector<const uint8_t> data(view.begin(), view.end());
+
+    if (op_code_token_queue_map_.count(view.GetCommandOpCode()) == 0) {
+      LOG_WARN("%s Received unexpected command complete for opcode:0x%04x", __func__, command_op_code);
+      return;
+    }
+    const void* token = op_code_token_queue_map_[view.GetCommandOpCode()].front();
+    if (token == nullptr) {
+      LOG_WARN("%s Received expected command status but no token for opcode:0x%04x", __func__, command_op_code);
+      return;
+    }
+
+    op_code_token_queue_map_[view.GetCommandOpCode()].pop();
+    command_complete_callback_(command_op_code, data, token);
+  }
+
+  void OnTransmitPacketStatus(hci::CommandStatusView view) {
+    if (command_status_callback_ == nullptr) {
+      LOG_WARN("%s Received packet complete with no status callback registered", __func__);
+      return;
+    }
+
+    uint16_t command_op_code = static_cast<uint16_t>(view.GetCommandOpCode());
+    std::vector<const uint8_t> data(view.begin(), view.end());
+
+    if (op_code_token_queue_map_.count(view.GetCommandOpCode()) == 0) {
+      LOG_WARN("%s Received unexpected command status for opcode:0x%04x", __func__, command_op_code);
+      return;
+    }
+    const void* token = op_code_token_queue_map_[view.GetCommandOpCode()].front();
+    if (token == nullptr) {
+      LOG_WARN("%s Received expected command status but no token for opcode:0x%04x", __func__, command_op_code);
+      return;
+    }
+
+    op_code_token_queue_map_[view.GetCommandOpCode()].pop();
+    uint8_t status = static_cast<uint8_t>(view.GetStatus());
+    command_status_callback_(command_op_code, data, token, status);
+  }
+
+  void TransmitCommand(uint16_t command, const uint8_t* data, size_t len, const void* token) {
+    ASSERT(data != nullptr);
+    ASSERT(token != nullptr);
+
+    const hci::OpCode op_code = static_cast<const hci::OpCode>(command);
+
+    auto payload = MakeUniquePacket(data, len);
+    auto packet = hci::CommandPacketBuilder::Create(op_code, std::move(payload));
+
+    op_code_token_queue_map_[op_code].push(token);
+    if (IsCommandStatusOpcode(op_code)) {
+      hci_layer_->EnqueueCommand(std::move(packet),
+                                 common::BindOnce(&impl::OnTransmitPacketStatus, common::Unretained(this)), handler_);
+    } else {
+      hci_layer_->EnqueueCommand(std::move(packet),
+                                 common::BindOnce(&impl::OnTransmitPacketCommandComplete, common::Unretained(this)),
+                                 handler_);
+    }
+  }
+
+  void RegisterCommandComplete(CommandCompleteCallback callback) {
+    ASSERT(command_complete_callback_ == nullptr);
+    command_complete_callback_ = callback;
+  }
+
+  void UnregisterCommandComplete() {
+    ASSERT(command_complete_callback_ != nullptr);
+    command_complete_callback_ = nullptr;
+  }
+
+  void RegisterCommandStatus(CommandStatusCallback callback) {
+    ASSERT(command_status_callback_ == nullptr);
+    command_status_callback_ = callback;
+  }
+
+  void UnregisterCommandStatus() {
+    ASSERT(command_status_callback_ != nullptr);
+    command_status_callback_ = nullptr;
+  }
+
+ private:
+  os::Handler* handler_{nullptr};
+  hci::HciLayer* hci_layer_{nullptr};
+
+  CommandCompleteCallback command_complete_callback_;
+  CommandStatusCallback command_status_callback_;
+
+  OpCodeTokenQueueMap op_code_token_queue_map_;
+
+  /**
+   * Returns true if expecting command complete, false otherwise
+   */
+  bool IsCommandStatusOpcode(hci::OpCode op_code) {
+    switch (op_code) {
+      case hci::OpCode::INQUIRY:
+      case hci::OpCode::CREATE_CONNECTION:
+      case hci::OpCode::DISCONNECT:
+      case hci::OpCode::ACCEPT_CONNECTION_REQUEST:
+      case hci::OpCode::REJECT_CONNECTION_REQUEST:
+      case hci::OpCode::CHANGE_CONNECTION_PACKET_TYPE:
+      case hci::OpCode::AUTHENTICATION_REQUESTED:
+      case hci::OpCode::SET_CONNECTION_ENCRYPTION:
+      case hci::OpCode::CHANGE_CONNECTION_LINK_KEY:
+      case hci::OpCode::MASTER_LINK_KEY:
+      case hci::OpCode::REMOTE_NAME_REQUEST:
+      case hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES:
+      case hci::OpCode::READ_REMOTE_EXTENDED_FEATURES:
+      case hci::OpCode::READ_REMOTE_VERSION_INFORMATION:
+      case hci::OpCode::READ_CLOCK_OFFSET:
+      case hci::OpCode::SETUP_SYNCHRONOUS_CONNECTION:
+      case hci::OpCode::ACCEPT_SYNCHRONOUS_CONNECTION:
+      case hci::OpCode::REJECT_SYNCHRONOUS_CONNECTION:
+      case hci::OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION:
+      case hci::OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION:
+      case hci::OpCode::HOLD_MODE:
+      case hci::OpCode::SNIFF_MODE:
+      case hci::OpCode::EXIT_SNIFF_MODE:
+      case hci::OpCode::QOS_SETUP:
+      case hci::OpCode::SWITCH_ROLE:
+      case hci::OpCode::FLOW_SPECIFICATION:
+      case hci::OpCode::REFRESH_ENCRYPTION_KEY:
+      case hci::OpCode::LE_CREATE_CONNECTION:
+      case hci::OpCode::LE_CONNECTION_UPDATE:
+      case hci::OpCode::LE_READ_REMOTE_FEATURES:
+      case hci::OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND:
+      case hci::OpCode::LE_GENERATE_DHKEY_COMMAND:
+      case hci::OpCode::LE_SET_PHY:
+      case hci::OpCode::LE_EXTENDED_CREATE_CONNECTION:
+      case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC:
+        return true;
+      default:
+        return false;
+    }
+  }
+
+  std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
+    packet::RawBuilder builder;
+    std::vector<uint8_t> bytes(data, data + len);
+
+    auto payload = std::make_unique<packet::RawBuilder>();
+    payload->AddOctets(bytes);
+
+    return payload;
+  }
+};
+
+void HciLayer::TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len, const void* token) {
+  pimpl_->TransmitCommand(op_code, data, len, std::move(token));
+}
+
+void HciLayer::RegisterCommandComplete(CommandCompleteCallback callback) {
+  pimpl_->RegisterCommandComplete(callback);
+}
+
+void HciLayer::UnregisterCommandComplete() {
+  pimpl_->UnregisterCommandComplete();
+}
+
+void HciLayer::RegisterCommandStatus(CommandStatusCallback callback) {
+  pimpl_->RegisterCommandStatus(callback);
+}
+
+void HciLayer::UnregisterCommandStatus() {
+  pimpl_->UnregisterCommandStatus();
+}
+
+/**
+ * Module methods
+ */
+void HciLayer::ListDependencies(ModuleList* list) {
+  list->add<hci::HciLayer>();
+}
+
+void HciLayer::Start() {
+  LOG_INFO("%s Starting controller shim layer", __func__);
+  pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::HciLayer>());
+}
+
+void HciLayer::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/hci_layer.h b/gd/shim/hci_layer.h
new file mode 100644
index 0000000..bcd7fed
--- /dev/null
+++ b/gd/shim/hci_layer.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <cstdint>
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/ihci_layer.h"
+
+/**
+ * The hci layer shim module that depends on the Gd hci layer module.
+ */
+namespace bluetooth {
+namespace shim {
+
+class HciLayer : public ::bluetooth::Module, public ::bluetooth::shim::IHciLayer {
+ public:
+  HciLayer() = default;
+  ~HciLayer() = default;
+
+  void TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len,
+                       const void* token);  // IHciLayer
+
+  void RegisterCommandComplete(CommandCompleteCallback callback);  // IHciLayer
+  void UnregisterCommandComplete();                                // IHciLayer
+
+  void RegisterCommandStatus(CommandStatusCallback callback);  // IHciLayer
+  void UnregisterCommandStatus();                              // IHciLayer
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(HciLayer);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/shim/iadvertising.h
similarity index 78%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/shim/iadvertising.h
index 8a08509..85a75c6 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/shim/iadvertising.h
@@ -13,13 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include "l2cap/classic_fixed_channel_service.h"
-
+/**
+ * The gd API exported to the legacy api
+ */
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+struct IAdvertising {
+  virtual ~IAdvertising() {}
+};
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/shim/iconnectability.h
similarity index 69%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/shim/iconnectability.h
index 8a08509..fbfaaa3 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/shim/iconnectability.h
@@ -13,13 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include "l2cap/classic_fixed_channel_service.h"
-
+/**
+ * The gd API exported to the legacy api
+ */
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+struct IConnectability {
+  virtual void StartConnectability() = 0;
+  virtual void StopConnectability() = 0;
+  virtual bool IsConnectable() const = 0;
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+  virtual ~IConnectability() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/icontroller.h b/gd/shim/icontroller.h
new file mode 100644
index 0000000..0accc66
--- /dev/null
+++ b/gd/shim/icontroller.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <cstdint>
+#include <string>
+
+/**
+ * The shim controller module that depends on the Gd controller module
+ */
+namespace bluetooth {
+namespace shim {
+
+typedef struct {
+  uint16_t le_data_packet_length;
+  uint8_t total_num_le_packets;
+} LeBufferSize;
+
+typedef struct {
+  uint16_t supported_max_tx_octets;
+  uint16_t supported_max_tx_time;
+  uint16_t supported_max_rx_octets;
+  uint16_t supported_max_rx_time;
+} LeMaximumDataLength;
+
+struct IController {
+  virtual bool IsCommandSupported(int op_code) const = 0;
+  virtual LeBufferSize GetControllerLeBufferSize() const = 0;
+  virtual LeMaximumDataLength GetControllerLeMaximumDataLength() const = 0;
+  virtual std::string GetControllerMacAddress() const = 0;
+  virtual uint16_t GetControllerAclPacketLength() const = 0;
+  virtual uint16_t GetControllerNumAclPacketBuffers() const = 0;
+  virtual uint64_t GetControllerLeLocalSupportedFeatures() const = 0;
+  virtual uint64_t GetControllerLeSupportedStates() const = 0;
+  virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const = 0;
+  virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const = 0;
+
+  virtual ~IController() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/shim/idiscoverability.h
similarity index 60%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/shim/idiscoverability.h
index 8a08509..2a2e4a8 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/shim/idiscoverability.h
@@ -13,13 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include "l2cap/classic_fixed_channel_service.h"
-
+/**
+ * The gd API exported to the legacy api
+ */
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+struct IDiscoverability {
+  virtual void StartGeneralDiscoverability() = 0;
+  virtual void StartLimitedDiscoverability() = 0;
+  virtual void StopDiscoverability() = 0;
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+  virtual bool IsGeneralDiscoverabilityEnabled() const = 0;
+  virtual bool IsLimitedDiscoverabilityEnabled() const = 0;
+
+  virtual ~IDiscoverability() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/ihci_layer.h b/gd/shim/ihci_layer.h
new file mode 100644
index 0000000..5bb8e8f
--- /dev/null
+++ b/gd/shim/ihci_layer.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <cstdint>
+#include <vector>
+
+/**
+ * Legacy interface and API into the Gd shim hci layer module.
+ */
+using CommandCompleteCallback =
+    std::function<void(uint16_t command_op_code, std::vector<const uint8_t> data, const void* token)>;
+using CommandStatusCallback =
+    std::function<void(uint16_t command_op_code, std::vector<const uint8_t> data, const void* token, uint8_t status)>;
+
+namespace bluetooth {
+namespace shim {
+
+struct IHciLayer {
+  virtual void TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len, const void* token) = 0;
+
+  virtual void RegisterCommandComplete(CommandCompleteCallback callback) = 0;
+  virtual void UnregisterCommandComplete() = 0;
+
+  virtual void RegisterCommandStatus(CommandStatusCallback callback) = 0;
+  virtual void UnregisterCommandStatus() = 0;
+
+  virtual ~IHciLayer() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/iinquiry.h b/gd/shim/iinquiry.h
new file mode 100644
index 0000000..97fd1b1
--- /dev/null
+++ b/gd/shim/iinquiry.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 <cstdint>
+#include <functional>
+#include <vector>
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+using InquiryResultCallback = std::function<void(std::vector<const uint8_t> data)>;
+using InquiryResultWithRssiCallback = std::function<void(std::vector<const uint8_t> data)>;
+using ExtendedInquiryResultCallback = std::function<void(std::vector<const uint8_t> data)>;
+using InquiryCompleteCallback = std::function<void(uint16_t status)>;
+using InquiryCancelCompleteCallback = std::function<void(uint8_t mode)>;
+
+struct IInquiry {
+  virtual void StartGeneralInquiry(uint8_t duration, uint8_t max_responses) = 0;
+  virtual void StartLimitedInquiry(uint8_t duration, uint8_t max_responses) = 0;
+  virtual void StopInquiry() = 0;
+  virtual bool IsGeneralInquiryActive() const = 0;
+  virtual bool IsLimitedInquiryActive() const = 0;
+
+  virtual void StartGeneralPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+                                           uint16_t min_delay) = 0;
+  virtual void StartLimitedPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+                                           uint16_t min_delay) = 0;
+  virtual void StopPeriodicInquiry() = 0;
+  virtual bool IsGeneralPeriodicInquiryActive() const = 0;
+  virtual bool IsLimitedPeriodicInquiryActive() const = 0;
+
+  virtual void SetInterlacedScan() = 0;
+  virtual void SetStandardScan() = 0;
+
+  virtual void SetScanActivity(uint16_t interval, uint16_t window) = 0;
+  virtual void GetScanActivity(uint16_t& interval, uint16_t& window) const = 0;
+
+  virtual void SetStandardInquiryResultMode() = 0;
+  virtual void SetInquiryWithRssiResultMode() = 0;
+  virtual void SetExtendedInquiryResultMode() = 0;
+
+  virtual void RegisterInquiryResult(InquiryResultCallback callback) = 0;
+  virtual void UnregisterInquiryResult() = 0;
+  virtual void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback) = 0;
+  virtual void UnregisterInquiryResultWithRssi() = 0;
+  virtual void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback) = 0;
+  virtual void UnregisterExtendedInquiryResult() = 0;
+  virtual void RegisterInquiryComplete(InquiryCompleteCallback callback) = 0;
+  virtual void UnregisterInquiryComplete() = 0;
+  virtual void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) = 0;
+  virtual void UnregisterInquiryCancelComplete() = 0;
+
+  virtual ~IInquiry() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/il2cap.h b/gd/shim/il2cap.h
new file mode 100644
index 0000000..994953e
--- /dev/null
+++ b/gd/shim/il2cap.h
@@ -0,0 +1,54 @@
+/*
+ * 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 <cstdint>
+#include <functional>
+#include <future>
+#include <string>
+#include <vector>
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+using ConnectionClosedCallback = std::function<void(uint16_t cid, int error_code)>;
+using ConnectionOpenCallback = std::function<void(std::string string_address, uint16_t psm, uint16_t cid)>;
+using ReadDataReadyCallback = std::function<void(uint16_t cid, std::vector<const uint8_t> data)>;
+
+struct IL2cap {
+  virtual void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) = 0;
+  virtual void UnregisterService(uint16_t psm) = 0;
+
+  virtual void CreateConnection(uint16_t psm, const std::string address, ConnectionOpenCallback on_open,
+                                std::promise<uint16_t> completed) = 0;
+  virtual void CloseConnection(uint16_t cid) = 0;
+
+  virtual void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) = 0;
+  virtual void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) = 0;
+
+  virtual void Write(uint16_t cid, const uint8_t* data, size_t len) = 0;
+  virtual void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0;
+  virtual void WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0;
+
+  virtual void SendLoopbackResponse(std::function<void()>) = 0;
+  virtual ~IL2cap() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/iname.h b/gd/shim/iname.h
new file mode 100644
index 0000000..c99ba37
--- /dev/null
+++ b/gd/shim/iname.h
@@ -0,0 +1,40 @@
+/*
+ * 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 <cstdint>
+#include <functional>
+#include <string>
+
+/**
+ * The gd API exported to the legacy api
+ */
+using ReadRemoteNameCallback =
+    std::function<void(std::string address_string, uint8_t hci_status, std::array<uint8_t, 248> remote_name)>;
+using CancelRemoteNameCallback = std::function<void(std::string address_string, uint8_t hci_status)>;
+
+namespace bluetooth {
+namespace shim {
+
+struct IName {
+  virtual void ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) = 0;
+  virtual void CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) = 0;
+
+  virtual ~IName() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/inquiry.cc b/gd/shim/inquiry.cc
new file mode 100644
index 0000000..4c3a174
--- /dev/null
+++ b/gd/shim/inquiry.cc
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/inquiry.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/inquiry.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Inquiry::impl {
+  void Result(hci::InquiryResultView view);
+  void ResultWithRssi(hci::InquiryResultWithRssiView view);
+  void ExtendedResult(hci::ExtendedInquiryResultView view);
+  void Complete(hci::ErrorCode status);
+
+  void RegisterInquiryResult(InquiryResultCallback callback);
+  void UnregisterInquiryResult();
+  void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback);
+  void UnregisterInquiryResultWithRssi();
+  void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback);
+  void UnregisterExtendedInquiryResult();
+  void RegisterInquiryComplete(InquiryCompleteCallback callback);
+  void UnregisterInquiryComplete();
+  void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback);
+  void UnregisterInquiryCancelComplete();
+
+  InquiryResultCallback shim_result_callback_;
+  InquiryResultWithRssiCallback shim_result_with_rssi_callback_;
+  ExtendedInquiryResultCallback shim_extended_result_callback_;
+  InquiryCompleteCallback shim_complete_callback_;
+  InquiryCancelCompleteCallback shim_cancel_complete_callback_;
+
+  neighbor::InquiryModule* module_{nullptr};
+
+  impl(neighbor::InquiryModule* module);
+  ~impl();
+};
+
+const ModuleFactory Inquiry::Factory = ModuleFactory([]() { return new Inquiry(); });
+
+void Inquiry::impl::Result(hci::InquiryResultView view) {
+  ASSERT(view.size() >= sizeof(uint16_t));
+  ASSERT(shim_result_callback_ != nullptr);
+  std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+  shim_result_callback_(v);
+}
+
+void Inquiry::impl::ResultWithRssi(hci::InquiryResultWithRssiView view) {
+  ASSERT(view.size() >= sizeof(uint16_t));
+  ASSERT(shim_result_with_rssi_callback_ != nullptr);
+  std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+  shim_result_with_rssi_callback_(v);
+}
+
+void Inquiry::impl::ExtendedResult(hci::ExtendedInquiryResultView view) {
+  ASSERT(view.size() >= sizeof(uint16_t));
+  ASSERT(shim_extended_result_callback_ != nullptr);
+  std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+  shim_extended_result_callback_(v);
+}
+
+void Inquiry::impl::Complete(hci::ErrorCode status) {
+  ASSERT(shim_complete_callback_ != nullptr);
+  shim_complete_callback_(static_cast<uint16_t>(status));
+}
+
+void Inquiry::impl::RegisterInquiryResult(shim::InquiryResultCallback callback) {
+  if (shim_result_callback_ != nullptr) {
+    LOG_WARN("Registering inquiry result without unregistering");
+  }
+  shim_result_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryResult() {
+  if (shim_result_callback_ == nullptr) {
+    LOG_WARN("Unregistering inquiry result without registering");
+  }
+  shim_result_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryResultWithRssi(shim::InquiryResultWithRssiCallback callback) {
+  if (shim_result_with_rssi_callback_ != nullptr) {
+    LOG_WARN("Registering inquiry result with rssi without unregistering");
+  }
+  shim_result_with_rssi_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryResultWithRssi() {
+  if (shim_result_with_rssi_callback_ == nullptr) {
+    LOG_WARN("Unregistering inquiry result with rssi without registering");
+  }
+  shim_result_with_rssi_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterExtendedInquiryResult(shim::ExtendedInquiryResultCallback callback) {
+  if (shim_result_with_rssi_callback_ != nullptr) {
+    LOG_WARN("Registering extended inquiry result without unregistering");
+  }
+  shim_extended_result_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterExtendedInquiryResult() {
+  if (shim_extended_result_callback_ == nullptr) {
+    LOG_WARN("Unregistering extended inquiry result without registering");
+  }
+  shim_extended_result_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryComplete(shim::InquiryCompleteCallback callback) {
+  if (shim_result_with_rssi_callback_ != nullptr) {
+    LOG_WARN("Registering inquiry complete without unregistering");
+  }
+  shim_complete_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryComplete() {
+  if (shim_result_with_rssi_callback_ == nullptr) {
+    LOG_WARN("Unregistering inquiry complete without registering");
+  }
+  shim_complete_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryCancelComplete(shim::InquiryCancelCompleteCallback callback) {
+  if (shim_cancel_complete_callback_ != nullptr) {
+    LOG_WARN("Registering inquiry cancel complete without unregistering");
+  }
+  shim_cancel_complete_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryCancelComplete() {
+  if (shim_cancel_complete_callback_ == nullptr) {
+    LOG_WARN("Unregistering inquiry cancel complete without registering");
+  }
+  shim_cancel_complete_callback_ = nullptr;
+}
+
+Inquiry::impl::impl(neighbor::InquiryModule* inquiry_module) : module_(inquiry_module) {
+  neighbor::InquiryCallbacks inquiry_callbacks;
+  inquiry_callbacks.result = std::bind(&Inquiry::impl::Result, this, std::placeholders::_1);
+  inquiry_callbacks.result_with_rssi = std::bind(&Inquiry::impl::ResultWithRssi, this, std::placeholders::_1);
+  inquiry_callbacks.extended_result = std::bind(&Inquiry::impl::ExtendedResult, this, std::placeholders::_1);
+  inquiry_callbacks.complete = std::bind(&Inquiry::impl::Complete, this, std::placeholders::_1);
+
+  module_->RegisterCallbacks(inquiry_callbacks);
+}
+
+Inquiry::impl::~impl() {
+  module_->UnregisterCallbacks();
+}
+
+void Inquiry::StartGeneralInquiry(uint8_t inquiry_length, uint8_t num_responses) {
+  return pimpl_->module_->StartGeneralInquiry(inquiry_length, num_responses);
+}
+
+void Inquiry::StartLimitedInquiry(uint8_t inquiry_length, uint8_t num_responses) {
+  return pimpl_->module_->StartLimitedInquiry(inquiry_length, num_responses);
+}
+
+void Inquiry::StopInquiry() {
+  return pimpl_->module_->StopInquiry();
+}
+
+bool Inquiry::IsGeneralInquiryActive() const {
+  return pimpl_->module_->IsGeneralInquiryActive();
+}
+
+bool Inquiry::IsLimitedInquiryActive() const {
+  return pimpl_->module_->IsLimitedInquiryActive();
+}
+
+void Inquiry::StartGeneralPeriodicInquiry(uint8_t inquiry_length, uint8_t num_responses, uint16_t max_delay,
+                                          uint16_t min_delay) {
+  return pimpl_->module_->StartGeneralPeriodicInquiry(inquiry_length, num_responses, max_delay, min_delay);
+}
+
+void Inquiry::StartLimitedPeriodicInquiry(uint8_t inquiry_length, uint8_t num_responses, uint16_t max_delay,
+                                          uint16_t min_delay) {
+  return pimpl_->module_->StartLimitedPeriodicInquiry(inquiry_length, num_responses, max_delay, min_delay);
+}
+
+void Inquiry::StopPeriodicInquiry() {
+  return pimpl_->module_->StopPeriodicInquiry();
+}
+
+bool Inquiry::IsGeneralPeriodicInquiryActive() const {
+  return pimpl_->module_->IsGeneralPeriodicInquiryActive();
+}
+
+bool Inquiry::IsLimitedPeriodicInquiryActive() const {
+  return pimpl_->module_->IsLimitedPeriodicInquiryActive();
+}
+
+void Inquiry::SetInterlacedScan() {
+  pimpl_->module_->SetInterlacedScan();
+}
+
+void Inquiry::SetStandardScan() {
+  pimpl_->module_->SetStandardScan();
+}
+
+void Inquiry::SetScanActivity(uint16_t interval, uint16_t window) {
+  neighbor::ScanParameters params{
+      .interval = static_cast<neighbor::ScanInterval>(interval),
+      .window = static_cast<neighbor::ScanWindow>(window),
+  };
+  pimpl_->module_->SetScanActivity(params);
+}
+
+void Inquiry::GetScanActivity(uint16_t& interval, uint16_t& window) const {
+  neighbor::ScanParameters params = pimpl_->module_->GetScanActivity();
+
+  interval = static_cast<uint16_t>(params.interval);
+  window = static_cast<uint16_t>(params.window);
+}
+
+void Inquiry::SetStandardInquiryResultMode() {
+  pimpl_->module_->SetStandardInquiryResultMode();
+}
+
+void Inquiry::SetInquiryWithRssiResultMode() {
+  pimpl_->module_->SetInquiryWithRssiResultMode();
+}
+
+void Inquiry::SetExtendedInquiryResultMode() {
+  pimpl_->module_->SetExtendedInquiryResultMode();
+}
+
+void Inquiry::RegisterInquiryResult(shim::InquiryResultCallback callback) {
+  pimpl_->RegisterInquiryResult(callback);
+}
+
+void Inquiry::UnregisterInquiryResult() {
+  pimpl_->UnregisterInquiryResult();
+}
+
+void Inquiry::RegisterInquiryResultWithRssi(shim::InquiryResultWithRssiCallback callback) {
+  pimpl_->RegisterInquiryResultWithRssi(callback);
+}
+
+void Inquiry::UnregisterInquiryResultWithRssi() {
+  pimpl_->UnregisterInquiryResultWithRssi();
+}
+
+void Inquiry::RegisterExtendedInquiryResult(shim::ExtendedInquiryResultCallback callback) {
+  pimpl_->RegisterExtendedInquiryResult(callback);
+}
+
+void Inquiry::UnregisterExtendedInquiryResult() {
+  pimpl_->UnregisterExtendedInquiryResult();
+}
+
+void Inquiry::RegisterInquiryComplete(InquiryCompleteCallback callback) {
+  pimpl_->RegisterInquiryComplete(callback);
+}
+
+void Inquiry::UnregisterInquiryComplete() {
+  pimpl_->UnregisterInquiryComplete();
+}
+
+void Inquiry::RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) {
+  pimpl_->RegisterInquiryCancelComplete(callback);
+}
+
+void Inquiry::UnregisterInquiryCancelComplete() {
+  pimpl_->UnregisterInquiryCancelComplete();
+}
+
+/**
+ * Module methods
+ */
+void Inquiry::ListDependencies(ModuleList* list) {
+  list->add<neighbor::InquiryModule>();
+}
+
+void Inquiry::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<neighbor::InquiryModule>());
+}
+
+void Inquiry::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/inquiry.h b/gd/shim/inquiry.h
new file mode 100644
index 0000000..9051d70
--- /dev/null
+++ b/gd/shim/inquiry.h
@@ -0,0 +1,81 @@
+/*
+ * 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 <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/iinquiry.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Inquiry : public bluetooth::Module, public bluetooth::shim::IInquiry {
+ public:
+  void StartGeneralInquiry(uint8_t duration, uint8_t max_responses) override;
+  void StartLimitedInquiry(uint8_t duration, uint8_t max_responses) override;
+  void StopInquiry() override;
+  bool IsGeneralInquiryActive() const override;
+  bool IsLimitedInquiryActive() const override;
+
+  void StartGeneralPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+                                   uint16_t min_delay) override;
+  void StartLimitedPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+                                   uint16_t min_delay) override;
+  void StopPeriodicInquiry() override;
+  bool IsGeneralPeriodicInquiryActive() const override;
+  bool IsLimitedPeriodicInquiryActive() const override;
+
+  void SetInterlacedScan() override;
+  void SetStandardScan() override;
+
+  void SetScanActivity(uint16_t interval, uint16_t window) override;
+  void GetScanActivity(uint16_t& interval, uint16_t& window) const override;
+
+  void SetStandardInquiryResultMode() override;
+  void SetInquiryWithRssiResultMode() override;
+  void SetExtendedInquiryResultMode() override;
+
+  void RegisterInquiryResult(InquiryResultCallback callback) override;
+  void UnregisterInquiryResult() override;
+  void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback) override;
+  void UnregisterInquiryResultWithRssi() override;
+  void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback) override;
+  void UnregisterExtendedInquiryResult() override;
+  void RegisterInquiryComplete(InquiryCompleteCallback callback) override;
+  void UnregisterInquiryComplete() override;
+  void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) override;
+  void UnregisterInquiryCancelComplete() override;
+
+  Inquiry() = default;
+  ~Inquiry() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Inquiry);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/shim/ipage.h
similarity index 62%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to gd/shim/ipage.h
index 8a08509..28c2762 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/shim/ipage.h
@@ -13,13 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include "l2cap/classic_fixed_channel_service.h"
+#include <cstdint>
 
+/**
+ * The gd API exported to the legacy api
+ */
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+struct IPage {
+  virtual void SetScanActivity(uint16_t interval, uint16_t window) = 0;
+  virtual void GetScanActivity(uint16_t& interval, uint16_t& window) const = 0;
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+  virtual void SetInterlacedScan() = 0;
+  virtual void SetStandardScan() = 0;
+
+  virtual ~IPage() {}
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/gd/shim/iscanning.h
similarity index 78%
rename from gd/l2cap/classic_fixed_channel_service.cc
rename to gd/shim/iscanning.h
index 8a08509..ddaabb6 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/gd/shim/iscanning.h
@@ -13,13 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#include "l2cap/classic_fixed_channel_service.h"
-
+/**
+ * The gd API exported to the legacy api
+ */
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+struct IScanning {
+  virtual ~IScanning() {}
+};
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/istack.h b/gd/shim/istack.h
new file mode 100644
index 0000000..f432dac
--- /dev/null
+++ b/gd/shim/istack.h
@@ -0,0 +1,58 @@
+/*
+ * 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
+
+/**
+ * Legacy stack manipulation methods to allow the legacy stack to start
+ * and stop the stack, and to provide Gd shim stack module API access.
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IAdvertising;
+struct IController;
+struct IConnectability;
+struct IDiscoverability;
+struct IHciLayer;
+struct IInquiry;
+struct IName;
+struct IL2cap;
+struct IPage;
+struct IScanning;
+
+struct IStack {
+  virtual void Start() = 0;
+  virtual void Stop() = 0;
+
+  virtual IAdvertising* GetAdvertising() = 0;
+  virtual IController* GetController() = 0;
+  virtual IConnectability* GetConnectability() = 0;
+  virtual IDiscoverability* GetDiscoverability() = 0;
+  virtual IHciLayer* GetHciLayer() = 0;
+  virtual IInquiry* GetInquiry() = 0;
+  virtual IName* GetName() = 0;
+  virtual IL2cap* GetL2cap() = 0;
+  virtual IPage* GetPage() = 0;
+  virtual IScanning* GetScanning() = 0;
+
+  virtual ~IStack() {}
+};
+
+IStack* GetGabeldorscheStack();
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/l2cap.cc b/gd/shim/l2cap.cc
new file mode 100644
index 0000000..d703972
--- /dev/null
+++ b/gd/shim/l2cap.cc
@@ -0,0 +1,526 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <cstdint>
+#include <functional>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+#include "shim/l2cap.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory L2cap::Factory = ModuleFactory([]() { return new L2cap(); });
+
+using ConnectionInterfaceDescriptor = uint16_t;
+static const ConnectionInterfaceDescriptor kInvalidConnectionInterfaceDescriptor = 0;
+static const ConnectionInterfaceDescriptor kStartConnectionInterfaceDescriptor = 64;
+static const ConnectionInterfaceDescriptor kMaxConnections = UINT16_MAX - kStartConnectionInterfaceDescriptor - 1;
+
+using ServiceInterfaceCallback =
+    std::function<void(l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result)>;
+using ConnectionInterfaceCallback =
+    std::function<void(l2cap::Psm psm, std::unique_ptr<l2cap::classic::DynamicChannel>)>;
+
+std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
+  packet::RawBuilder builder;
+  std::vector<uint8_t> bytes(data, data + len);
+  auto payload = std::make_unique<packet::RawBuilder>();
+  payload->AddOctets(bytes);
+  return payload;
+}
+
+class ConnectionInterface {
+ public:
+  ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel,
+                      os::Handler* handler)
+      : cid_(cid), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_(nullptr),
+        on_connection_closed_callback_(nullptr), address_(channel_->GetDevice()) {
+    channel_->RegisterOnCloseCallback(
+        handler_, common::BindOnce(&ConnectionInterface::OnConnectionClosed, common::Unretained(this)));
+    channel_->GetQueueUpEnd()->RegisterDequeue(
+        handler_, common::Bind(&ConnectionInterface::OnReadReady, common::Unretained(this)));
+    dequeue_registered_ = true;
+  }
+
+  ~ConnectionInterface() {
+    ASSERT(!dequeue_registered_);
+  }
+
+  void OnReadReady() {
+    std::unique_ptr<packet::PacketView<packet::kLittleEndian>> packet = channel_->GetQueueUpEnd()->TryDequeue();
+    if (packet == nullptr) {
+      LOG_WARN("Got read ready from gd l2cap but no packet is ready");
+      return;
+    }
+    std::vector<const uint8_t> data(packet->begin(), packet->end());
+    ASSERT(on_data_ready_callback_ != nullptr);
+    on_data_ready_callback_(cid_, data);
+  }
+
+  void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) {
+    ASSERT(on_data_ready != nullptr);
+    ASSERT(on_data_ready_callback_ == nullptr);
+    on_data_ready_callback_ = on_data_ready;
+  }
+
+  std::unique_ptr<packet::BasePacketBuilder> WriteReady() {
+    auto data = std::move(write_queue_.front());
+    write_queue_.pop();
+    if (write_queue_.empty()) {
+      channel_->GetQueueUpEnd()->UnregisterEnqueue();
+      enqueue_registered_ = false;
+    }
+    return data;
+  }
+
+  void Write(std::unique_ptr<packet::RawBuilder> packet) {
+    LOG_DEBUG("Writing packet cid:%hd size:%zd", cid_, packet->size());
+    write_queue_.push(std::move(packet));
+    if (!enqueue_registered_) {
+      enqueue_registered_ = true;
+      channel_->GetQueueUpEnd()->RegisterEnqueue(
+          handler_, common::Bind(&ConnectionInterface::WriteReady, common::Unretained(this)));
+    }
+  }
+
+  void Close() {
+    if (dequeue_registered_) {
+      channel_->GetQueueUpEnd()->UnregisterDequeue();
+      dequeue_registered_ = false;
+    }
+    ASSERT(write_queue_.empty());
+    channel_->Close();
+  }
+
+  void OnConnectionClosed(hci::ErrorCode error_code) {
+    LOG_DEBUG("Channel interface closed reason:%s cid:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), cid_,
+              address_.ToString().c_str());
+    ASSERT(on_connection_closed_callback_ != nullptr);
+    on_connection_closed_callback_(cid_, static_cast<int>(error_code));
+  }
+
+  void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) {
+    ASSERT(on_connection_closed != nullptr);
+    ASSERT(on_connection_closed_callback_ == nullptr);
+    on_connection_closed_callback_ = std::move(on_connection_closed);
+  }
+
+ private:
+  const ConnectionInterfaceDescriptor cid_;
+  const std::unique_ptr<l2cap::classic::DynamicChannel> channel_;
+  os::Handler* handler_;
+
+  ReadDataReadyCallback on_data_ready_callback_;
+  ConnectionClosedCallback on_connection_closed_callback_;
+
+  const hci::Address address_;
+
+  std::queue<std::unique_ptr<packet::PacketBuilder<hci::kLittleEndian>>> write_queue_;
+
+  bool enqueue_registered_{false};
+  bool dequeue_registered_{false};
+};
+
+struct ConnectionInterfaceManager {
+ public:
+  ConnectionInterfaceDescriptor AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel);
+  void RemoveConnection(ConnectionInterfaceDescriptor cid);
+
+  void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
+  void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
+
+  bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
+
+  size_t NumberOfActiveConnections() const {
+    return cid_to_interface_map_.size();
+  }
+
+  void GeneralCallback(ConnectionOpenCallback on_open, hci::Address address, l2cap::Psm psm,
+                       ConnectionInterfaceDescriptor cid) {
+    on_open(address.ToString(), static_cast<uint16_t>(psm), static_cast<uint16_t>(cid));
+  }
+
+  void ConnectionOpened(ConnectionOpenCallback on_open, hci::Address address, l2cap::Psm psm,
+                        ConnectionInterfaceDescriptor cid) {
+    LOG_DEBUG("%s address:%s psm:%hd cid:%hd", __func__, address.ToString().c_str(), psm, cid);
+    handler_->Post(common::BindOnce(&ConnectionInterfaceManager::GeneralCallback, common::Unretained(this), on_open,
+                                    address, psm, cid));
+    // TODO(cmanton) queue this pending connection address/psm tuple up for deletion
+    // There may be multiple, so only remove one
+  }
+
+  void ConnectionFailed(hci::Address address, l2cap::Psm psm) {
+    LOG_DEBUG("%s Connection Failed", __func__);
+    // TODO(cmanton) queue this pending connection address/psm tuple up for deletion
+    // There may be multiple, so only remove one
+  }
+
+  ConnectionInterfaceManager(os::Handler* handler);
+
+ private:
+  os::Handler* handler_;
+  ConnectionInterfaceDescriptor current_connection_interface_descriptor_;
+
+  bool HasResources() const;
+  bool Exists(ConnectionInterfaceDescriptor id) const;
+
+  std::unordered_map<ConnectionInterfaceDescriptor, std::unique_ptr<ConnectionInterface>> cid_to_interface_map_;
+  ConnectionInterfaceDescriptor AllocateConnectionInterfaceDescriptor();
+  ConnectionInterfaceManager() = delete;
+};
+
+ConnectionInterfaceManager::ConnectionInterfaceManager(os::Handler* handler)
+    : handler_(handler), current_connection_interface_descriptor_(kStartConnectionInterfaceDescriptor) {}
+
+bool ConnectionInterfaceManager::Exists(ConnectionInterfaceDescriptor cid) const {
+  return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end();
+}
+
+ConnectionInterfaceDescriptor ConnectionInterfaceManager::AllocateConnectionInterfaceDescriptor() {
+  ASSERT(HasResources());
+  while (Exists(current_connection_interface_descriptor_)) {
+    if (++current_connection_interface_descriptor_ == kInvalidConnectionInterfaceDescriptor) {
+      current_connection_interface_descriptor_ = kStartConnectionInterfaceDescriptor;
+    }
+  }
+  return current_connection_interface_descriptor_++;
+}
+
+ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel(
+    std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+  if (!HasResources()) {
+    return kInvalidConnectionInterfaceDescriptor;
+  }
+  ConnectionInterfaceDescriptor cid = AllocateConnectionInterfaceDescriptor();
+
+  auto channel_interface = std::make_unique<ConnectionInterface>(cid, std::move(channel), handler_);
+  cid_to_interface_map_[cid] = std::move(channel_interface);
+  return cid;
+}
+
+void ConnectionInterfaceManager::RemoveConnection(ConnectionInterfaceDescriptor cid) {
+  ASSERT(cid_to_interface_map_.count(cid) == 1);
+  cid_to_interface_map_.find(cid)->second->Close();
+  cid_to_interface_map_.erase(cid);
+}
+
+bool ConnectionInterfaceManager::HasResources() const {
+  return cid_to_interface_map_.size() < kMaxConnections;
+}
+
+void ConnectionInterfaceManager::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid,
+                                                          ReadDataReadyCallback on_data_ready) {
+  ASSERT(Exists(cid));
+  return cid_to_interface_map_[cid]->SetReadDataReadyCallback(on_data_ready);
+}
+
+void ConnectionInterfaceManager::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid,
+                                                             ConnectionClosedCallback on_closed) {
+  ASSERT(Exists(cid));
+  return cid_to_interface_map_[cid]->SetConnectionClosedCallback(on_closed);
+}
+
+bool ConnectionInterfaceManager::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
+  if (!Exists(cid)) {
+    return false;
+  }
+  cid_to_interface_map_[cid]->Write(std::move(packet));
+  return true;
+}
+
+class PendingConnection {
+ public:
+  PendingConnection(ConnectionInterfaceManager* connection_interface_manager, l2cap::Psm psm, hci::Address address,
+                    ConnectionOpenCallback on_open, std::promise<uint16_t> completed)
+      : connection_interface_manager_(connection_interface_manager), psm_(psm), address_(address),
+        on_open_(std::move(on_open)), completed_(std::move(completed)) {}
+
+  void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+    LOG_DEBUG("Local initiated connection is open to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
+    ConnectionInterfaceDescriptor cid = connection_interface_manager_->AddChannel(std::move(channel));
+    completed_.set_value(cid);
+    // Attempt to avoid async race condition with upper stack
+    std::this_thread::yield();
+    connection_interface_manager_->ConnectionOpened(std::move(on_open_), address_, psm_, cid);
+  }
+
+  void OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) {
+    LOG_DEBUG("Connection failed to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
+    switch (result.connection_result_code) {
+      case l2cap::classic::DynamicChannelManager::ConnectionResultCode::SUCCESS:
+        LOG_WARN("Connection failed result:success hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
+        break;
+      case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED:
+        LOG_DEBUG("Connection failed result:no service registered hci:%s",
+                  hci::ErrorCodeText(result.hci_error).c_str());
+        break;
+      case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR:
+        LOG_DEBUG("Connection failed result:hci error hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
+        break;
+      case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_L2CAP_ERROR:
+        LOG_DEBUG("Connection failed result:l2cap error hci:%s l2cap:%s", hci::ErrorCodeText(result.hci_error).c_str(),
+                  l2cap::ConnectionResponseResultText(result.l2cap_connection_response_result).c_str());
+        break;
+    }
+    completed_.set_value(kInvalidConnectionInterfaceDescriptor);
+    connection_interface_manager_->ConnectionFailed(address_, psm_);
+  }
+
+ private:
+  ConnectionInterfaceManager* connection_interface_manager_;
+  const l2cap::Psm psm_;
+  const hci::Address address_;
+  ConnectionOpenCallback on_open_;
+  std::promise<uint16_t> completed_;
+};
+
+class ServiceInterface {
+ public:
+  ServiceInterface(ConnectionInterfaceManager* connection_interface_manager, l2cap::Psm psm,
+                   ConnectionOpenCallback on_open, std::promise<void> completed)
+      : connection_interface_manager_(connection_interface_manager), psm_(psm), on_open_(on_open),
+        completed_(std::move(completed)) {}
+
+  void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result,
+                              std::unique_ptr<l2cap::classic::DynamicChannelService> service) {
+    ASSERT(service_ == nullptr);
+    ASSERT(psm_ == service->GetPsm());
+    LOG_DEBUG("Registration is complete for psm:%hd", psm_);
+    service_ = std::move(service);
+    completed_.set_value();
+  }
+
+  void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+    LOG_DEBUG("Remote initiated connection is open from device:%s for psm:%hd", channel->GetDevice().ToString().c_str(),
+              psm_);
+    hci::Address address = channel->GetDevice();
+    ConnectionInterfaceDescriptor cid = connection_interface_manager_->AddChannel(std::move(channel));
+    connection_interface_manager_->ConnectionOpened(on_open_, address, psm_, cid);
+  }
+
+  l2cap::SecurityPolicy GetSecurityPolicy() const {
+    return security_policy_;
+  }
+
+  void RegisterService(
+      std::function<void(l2cap::Psm, l2cap::SecurityPolicy security_policy,
+                         l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+                         l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open)>
+          func) {
+    func(psm_, security_policy_, common::BindOnce(&ServiceInterface::OnRegistrationComplete, common::Unretained(this)),
+         common::Bind(&ServiceInterface::OnConnectionOpen, common::Unretained(this)));
+  }
+
+ private:
+  ConnectionInterfaceManager* connection_interface_manager_;
+  const l2cap::Psm psm_;
+  ConnectionOpenCallback on_open_;
+  std::promise<void> completed_;
+
+  std::unique_ptr<l2cap::classic::DynamicChannelService> service_;
+
+  const l2cap::SecurityPolicy security_policy_;
+};
+
+struct L2cap::impl {
+  void RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed);
+  void UnregisterService(l2cap::Psm psm);
+
+  void CreateConnection(l2cap::Psm psm, hci::Address address, ConnectionOpenCallback on_open,
+                        std::promise<uint16_t> completed);
+  void CloseConnection(ConnectionInterfaceDescriptor cid);
+
+  void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
+  void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
+
+  void Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
+
+  void SendLoopbackResponse(std::function<void()> function);
+
+  impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module);
+
+ private:
+  L2cap& module_;
+  l2cap::classic::L2capClassicModule* l2cap_module_;
+  os::Handler* handler_;
+  ConnectionInterfaceManager connection_interface_manager_;
+
+  std::unique_ptr<l2cap::classic::DynamicChannelManager> dynamic_channel_manager_;
+
+  std::unordered_map<l2cap::Psm, std::shared_ptr<ServiceInterface>> psm_to_service_interface_map_;
+  std::unordered_map<l2cap::Psm, std::shared_ptr<PendingConnection>> psm_to_pending_connection_map_;
+};
+
+L2cap::impl::impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module)
+    : module_(module), l2cap_module_(l2cap_module), handler_(module_.GetHandler()),
+      connection_interface_manager_(handler_) {
+  dynamic_channel_manager_ = l2cap_module_->GetDynamicChannelManager();
+}
+
+void L2cap::impl::RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed) {
+  ASSERT(psm_to_service_interface_map_.find(psm) == psm_to_service_interface_map_.end());
+
+  auto service_interface =
+      std::make_shared<ServiceInterface>(&connection_interface_manager_, psm, on_open, std::move(completed));
+  psm_to_service_interface_map_.emplace(psm, service_interface);
+
+  // TODO(cmanton): Use the configuration option from user
+  service_interface->RegisterService(
+      [this](l2cap::Psm psm, l2cap::SecurityPolicy security_policy,
+             l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+             l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open) {
+        bool rc = dynamic_channel_manager_->RegisterService(psm, l2cap::classic::DynamicChannelConfigurationOption(),
+                                                            security_policy, std::move(on_registration_complete),
+                                                            on_connection_open, handler_);
+        ASSERT_LOG(rc == true, "Failed to register classic service");
+      });
+}
+
+void L2cap::impl::UnregisterService(l2cap::Psm psm) {
+  psm_to_service_interface_map_.erase(psm);
+}
+
+void L2cap::impl::CreateConnection(l2cap::Psm psm, hci::Address address, ConnectionOpenCallback on_open,
+                                   std::promise<uint16_t> completed) {
+  LOG_DEBUG("Initiating classic connection to psm:%hd device:%s", psm, address.ToString().c_str());
+  auto pending_connection = std::make_shared<PendingConnection>(&connection_interface_manager_, psm, address,
+                                                                std::move(on_open), std::move(completed));
+  // TODO(cmanton) hash psm/address pair into unordered map for pending_connection
+  // This is ok for now
+  psm_to_pending_connection_map_[psm] = pending_connection;
+  // TODO(cmanton): Add ERTM mode support by changing configuratio_option in ConnectChannel()
+  bool rc = dynamic_channel_manager_->ConnectChannel(
+      address, l2cap::classic::DynamicChannelConfigurationOption(), psm,
+      common::Bind(&PendingConnection::OnConnectionOpen, common::Unretained(pending_connection.get())),
+      common::BindOnce(&PendingConnection::OnConnectionFailure, common::Unretained(pending_connection.get())),
+      handler_);
+  ASSERT_LOG(rc == true, "Failed to create classic connection");
+}
+
+void L2cap::impl::CloseConnection(ConnectionInterfaceDescriptor cid) {
+  connection_interface_manager_.RemoveConnection(cid);
+}
+
+void L2cap::impl::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready) {
+  connection_interface_manager_.SetReadDataReadyCallback(cid, on_data_ready);
+}
+
+void L2cap::impl::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed) {
+  connection_interface_manager_.SetConnectionClosedCallback(cid, std::move(on_closed));
+}
+
+void L2cap::impl::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
+  connection_interface_manager_.Write(cid, std::move(packet));
+}
+
+void L2cap::impl::SendLoopbackResponse(std::function<void()> function) {
+  function();
+}
+
+void L2cap::RegisterService(uint16_t raw_psm, ConnectionOpenCallback on_open, std::promise<void> completed) {
+  l2cap::Psm psm{raw_psm};
+  GetHandler()->Post(common::BindOnce(&L2cap::impl::RegisterService, common::Unretained(pimpl_.get()), psm, on_open,
+                                      std::move(completed)));
+}
+
+void L2cap::UnregisterService(uint16_t raw_psm) {
+  l2cap::Psm psm{raw_psm};
+  GetHandler()->Post(common::Bind(&L2cap::impl::UnregisterService, common::Unretained(pimpl_.get()), psm));
+}
+
+void L2cap::CreateConnection(uint16_t raw_psm, const std::string address_string, ConnectionOpenCallback on_open,
+                             std::promise<uint16_t> completed) {
+  l2cap::Psm psm{raw_psm};
+  hci::Address address;
+  hci::Address::FromString(address_string, address);
+
+  GetHandler()->Post(common::BindOnce(&L2cap::impl::CreateConnection, common::Unretained(pimpl_.get()), psm, address,
+                                      on_open, std::move(completed)));
+}
+
+void L2cap::CloseConnection(uint16_t raw_cid) {
+  ConnectionInterfaceDescriptor cid(raw_cid);
+  GetHandler()->Post(common::Bind(&L2cap::impl::CloseConnection, common::Unretained(pimpl_.get()), cid));
+}
+
+void L2cap::SetReadDataReadyCallback(uint16_t raw_cid, ReadDataReadyCallback on_data_ready) {
+  ConnectionInterfaceDescriptor cid(raw_cid);
+  GetHandler()->Post(
+      common::Bind(&L2cap::impl::SetReadDataReadyCallback, common::Unretained(pimpl_.get()), cid, on_data_ready));
+}
+
+void L2cap::SetConnectionClosedCallback(uint16_t raw_cid, ConnectionClosedCallback on_closed) {
+  ConnectionInterfaceDescriptor cid(raw_cid);
+  GetHandler()->Post(common::Bind(&L2cap::impl::SetConnectionClosedCallback, common::Unretained(pimpl_.get()), cid,
+                                  std::move(on_closed)));
+}
+
+void L2cap::Write(uint16_t raw_cid, const uint8_t* data, size_t len) {
+  ConnectionInterfaceDescriptor cid(raw_cid);
+  auto packet = MakeUniquePacket(data, len);
+  GetHandler()->Post(common::BindOnce(&L2cap::impl::Write, common::Unretained(pimpl_.get()), cid, std::move(packet)));
+}
+
+void L2cap::WriteFlushable(uint16_t raw_cid, const uint8_t* data, size_t len) {
+  LOG_WARN("UNIMPLEMENTED Write flushable");
+  return Write(raw_cid, data, len);
+}
+
+void L2cap::WriteNonFlushable(uint16_t raw_cid, const uint8_t* data, size_t len) {
+  LOG_WARN("UNIMPLEMENTED Write non flushable");
+  return Write(raw_cid, data, len);
+}
+
+void L2cap::SendLoopbackResponse(std::function<void()> function) {
+  GetHandler()->Post(common::BindOnce(&L2cap::impl::SendLoopbackResponse, common::Unretained(pimpl_.get()), function));
+}
+
+/**
+ * Module methods
+ */
+void L2cap::ListDependencies(ModuleList* list) {
+  list->add<l2cap::classic::L2capClassicModule>();
+}
+
+void L2cap::Start() {
+  pimpl_ = std::make_unique<impl>(*this, GetDependency<l2cap::classic::L2capClassicModule>());
+}
+
+void L2cap::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/l2cap.h b/gd/shim/l2cap.h
new file mode 100644
index 0000000..955d20c
--- /dev/null
+++ b/gd/shim/l2cap.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <cstdint>
+#include <functional>
+#include <future>
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/il2cap.h"
+
+namespace bluetooth {
+namespace shim {
+
+class L2cap : public bluetooth::Module, public bluetooth::shim::IL2cap {
+ public:
+  void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) override;
+  void UnregisterService(uint16_t psm) override;
+
+  void CreateConnection(uint16_t psm, const std::string address_string, ConnectionOpenCallback on_open,
+                        std::promise<uint16_t> completed) override;
+  void CloseConnection(uint16_t cid) override;
+
+  void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) override;
+  void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) override;
+
+  void Write(uint16_t cid, const uint8_t* data, size_t len) override;
+  void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+  void WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+
+  void SendLoopbackResponse(std::function<void()>) override;
+
+  L2cap() = default;
+  ~L2cap() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(L2cap);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/name.cc b/gd/shim/name.cc
new file mode 100644
index 0000000..582d1ed
--- /dev/null
+++ b/gd/shim/name.cc
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/name.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/name.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Name::impl {
+  void ReadRemoteNameRequest(const hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+                             uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+                             ReadRemoteNameCallback callback);
+  void CancelRemoteNameRequest(const hci::Address address, CancelRemoteNameCallback callback);
+
+  void OnReadRemoteName(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name);
+  void OnCancelRemoteName(hci::ErrorCode status, hci::Address address);
+
+  impl(neighbor::NameModule* module, os::Handler* handler);
+  ~impl();
+
+ private:
+  std::unordered_map<hci::Address, ReadRemoteNameCallback> address_to_read_remote_callback_map_;
+  std::unordered_map<hci::Address, CancelRemoteNameCallback> address_to_cancel_remote_callback_map_;
+
+  neighbor::NameModule* module_{nullptr};
+  os::Handler* handler_;
+};
+
+const ModuleFactory Name::Factory = ModuleFactory([]() { return new Name(); });
+
+void Name::impl::OnReadRemoteName(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name) {
+  LOG_DEBUG("%s from %s", __func__, address.ToString().c_str());
+  ASSERT(address_to_read_remote_callback_map_.find(address) != address_to_read_remote_callback_map_.end());
+  ReadRemoteNameCallback callback = address_to_read_remote_callback_map_[address];
+  address_to_read_remote_callback_map_.erase(address);
+  callback(address.ToString(), static_cast<uint8_t>(status), name);
+}
+
+void Name::impl::OnCancelRemoteName(hci::ErrorCode status, hci::Address address) {
+  LOG_DEBUG("%s from %s", __func__, address.ToString().c_str());
+  ASSERT(address_to_cancel_remote_callback_map_.find(address) != address_to_cancel_remote_callback_map_.end());
+  CancelRemoteNameCallback callback = address_to_cancel_remote_callback_map_[address];
+  address_to_cancel_remote_callback_map_.erase(address);
+  callback(address.ToString(), static_cast<uint8_t>(status));
+}
+
+void Name::impl::ReadRemoteNameRequest(const hci::Address address,
+                                       hci::PageScanRepetitionMode page_scan_repetition_mode, uint16_t clock_offset,
+                                       hci::ClockOffsetValid clock_offset_valid, ReadRemoteNameCallback callback) {
+  ASSERT(address_to_read_remote_callback_map_.find(address) == address_to_read_remote_callback_map_.end());
+  address_to_read_remote_callback_map_[address] = callback;
+  module_->ReadRemoteNameRequest(address, page_scan_repetition_mode, clock_offset, clock_offset_valid,
+                                 common::BindOnce(&Name::impl::OnReadRemoteName, common::Unretained(this)), handler_);
+}
+
+void Name::impl::CancelRemoteNameRequest(const hci::Address address, CancelRemoteNameCallback callback) {
+  ASSERT(address_to_cancel_remote_callback_map_.find(address) == address_to_cancel_remote_callback_map_.end());
+  address_to_cancel_remote_callback_map_[address] = callback;
+  module_->CancelRemoteNameRequest(address, common::BindOnce(&Name::impl::OnCancelRemoteName, common::Unretained(this)),
+                                   handler_);
+}
+
+Name::impl::impl(neighbor::NameModule* module, os::Handler* handler) : module_(module), handler_(handler) {}
+
+Name::impl::~impl() {}
+
+void Name::ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) {
+  hci::Address address;
+  hci::Address::FromString(remote_address, address);
+
+  // TODO(cmanton) Use remote name request defaults for now
+  hci::PageScanRepetitionMode page_scan_repetition_mode = hci::PageScanRepetitionMode::R1;
+  uint16_t clock_offset = 0;
+  hci::ClockOffsetValid clock_offset_valid = hci::ClockOffsetValid::INVALID;
+  pimpl_->ReadRemoteNameRequest(address, page_scan_repetition_mode, clock_offset, clock_offset_valid, callback);
+}
+
+void Name::CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) {
+  hci::Address address;
+  hci::Address::FromString(remote_address, address);
+  pimpl_->CancelRemoteNameRequest(address, callback);
+}
+
+/**
+ * Module methods
+ */
+void Name::ListDependencies(ModuleList* list) {
+  list->add<neighbor::NameModule>();
+}
+
+void Name::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<neighbor::NameModule>(), GetHandler());
+}
+
+void Name::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/name.h b/gd/shim/name.h
new file mode 100644
index 0000000..7d8233f
--- /dev/null
+++ b/gd/shim/name.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <memory>
+
+#include "module.h"
+#include "shim/iname.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Name : public bluetooth::Module, public bluetooth::shim::IName {
+ public:
+  void ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) override;
+  void CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) override;
+
+  Name() = default;
+  ~Name() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Name);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/only_include_this_file_into_legacy_stack___ever.h b/gd/shim/only_include_this_file_into_legacy_stack___ever.h
new file mode 100644
index 0000000..335778a
--- /dev/null
+++ b/gd/shim/only_include_this_file_into_legacy_stack___ever.h
@@ -0,0 +1,37 @@
+/*
+ * 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
+
+/**
+ * This common file provides the only visibility from the legacy stack into GD stack.
+ *
+ * Only interfaces or APIs should be exported.
+ *
+ * Only common data structures should be used to pass data between the stacks.
+ *
+ */
+#include "gd/shim/iadvertising.h"
+#include "gd/shim/iconnectability.h"
+#include "gd/shim/icontroller.h"
+#include "gd/shim/idiscoverability.h"
+#include "gd/shim/ihci_layer.h"
+#include "gd/shim/iinquiry.h"
+#include "gd/shim/il2cap.h"
+#include "gd/shim/iname.h"
+#include "gd/shim/ipage.h"
+#include "gd/shim/iscanning.h"
+#include "gd/shim/istack.h"
diff --git a/gd/shim/page.cc b/gd/shim/page.cc
new file mode 100644
index 0000000..aa79d29
--- /dev/null
+++ b/gd/shim/page.cc
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/page.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/page.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Page::Factory = ModuleFactory([]() { return new Page(); });
+
+struct Page::impl {
+  impl(neighbor::PageModule* module);
+  ~impl();
+
+  neighbor::PageModule* module_{nullptr};
+};
+
+Page::impl::impl(neighbor::PageModule* module) : module_(module) {}
+
+Page::impl::~impl() {}
+
+void Page::SetScanActivity(uint16_t interval, uint16_t window) {
+  neighbor::ScanParameters params{.interval = static_cast<neighbor::ScanInterval>(interval),
+                                  .window = static_cast<neighbor::ScanWindow>(window)};
+  return pimpl_->module_->SetScanActivity(params);
+}
+
+void Page::GetScanActivity(uint16_t& interval, uint16_t& window) const {
+  neighbor::ScanParameters params = pimpl_->module_->GetScanActivity();
+
+  interval = static_cast<uint16_t>(params.interval);
+  window = static_cast<uint16_t>(params.window);
+}
+
+void Page::SetInterlacedScan() {
+  return pimpl_->module_->SetInterlacedScan();
+}
+void Page::SetStandardScan() {
+  return pimpl_->module_->SetStandardScan();
+}
+
+/**
+ * Module methods
+ */
+void Page::ListDependencies(ModuleList* list) {
+  list->add<neighbor::PageModule>();
+}
+
+void Page::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<neighbor::PageModule>());
+}
+
+void Page::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/page.h b/gd/shim/page.h
new file mode 100644
index 0000000..b4e71cd
--- /dev/null
+++ b/gd/shim/page.h
@@ -0,0 +1,51 @@
+/*
+ * 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 <memory>
+
+#include "module.h"
+#include "shim/ipage.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Page : public bluetooth::Module, public bluetooth::shim::IPage {
+ public:
+  void SetScanActivity(uint16_t interval, uint16_t window) override;
+  void GetScanActivity(uint16_t& interval, uint16_t& window) const override;
+
+  void SetInterlacedScan() override;
+  void SetStandardScan() override;
+
+  Page() = default;
+  ~Page() = default;
+
+  static const ModuleFactory Factory;
+
+ protected:
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Page);
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/scanning.cc b/gd/shim/scanning.cc
new file mode 100644
index 0000000..5216937
--- /dev/null
+++ b/gd/shim/scanning.cc
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "hci/le_scanning_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/scanning.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Scanning::impl {
+  hci::LeScanningManager* module_{nullptr};
+
+  impl(hci::LeScanningManager* module);
+  ~impl();
+};
+
+const ModuleFactory Scanning::Factory = ModuleFactory([]() { return new Scanning(); });
+
+Scanning::impl::impl(hci::LeScanningManager* scanning_manager) : module_(scanning_manager) {}
+
+Scanning::impl::~impl() {}
+
+/**
+ * Module methods
+ */
+void Scanning::ListDependencies(ModuleList* list) {
+  list->add<hci::LeScanningManager>();
+}
+
+void Scanning::Start() {
+  pimpl_ = std::make_unique<impl>(GetDependency<hci::LeScanningManager>());
+}
+
+void Scanning::Stop() {
+  pimpl_.reset();
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/l2cap_layer.h b/gd/shim/scanning.h
similarity index 61%
copy from gd/l2cap/l2cap_layer.h
copy to gd/shim/scanning.h
index 2e2aa60..8768ead 100644
--- a/gd/l2cap/l2cap_layer.h
+++ b/gd/shim/scanning.h
@@ -16,37 +16,31 @@
 #pragma once
 
 #include <memory>
+#include <string>
 
-#include "l2cap/classic_fixed_channel_manager.h"
 #include "module.h"
+#include "shim/iscanning.h"
 
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-class L2capLayer : public bluetooth::Module {
+class Scanning : public bluetooth::Module, public bluetooth::shim::IScanning {
  public:
-  L2capLayer() = default;
-  ~L2capLayer() = default;
+  Scanning() = default;
+  ~Scanning() = default;
 
   static const ModuleFactory Factory;
 
  protected:
-  void ListDependencies(ModuleList* list) override;
-
-  void Start() override;
-
-  void Stop() override;
-
-  /**
-   * Get the api to the classic channel l2cap module
-   */
-  std::unique_ptr<ClassicFixedChannelManager> GetClassicFixedChannelManager();
+  void ListDependencies(ModuleList* list) override;  // Module
+  void Start() override;                             // Module
+  void Stop() override;                              // Module
 
  private:
   struct impl;
-  std::unique_ptr<impl> impl_;
-  DISALLOW_COPY_AND_ASSIGN(L2capLayer);
+  std::unique_ptr<impl> pimpl_;
+  DISALLOW_COPY_AND_ASSIGN(Scanning);
 };
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/shim/stack.cc b/gd/shim/stack.cc
new file mode 100644
index 0000000..7822a35
--- /dev/null
+++ b/gd/shim/stack.cc
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_gd_shim"
+
+#include "shim/stack.h"
+#include "hal/hci_hal.h"
+#include "hci/acl_manager.h"
+#include "hci/classic_security_manager.h"
+#include "hci/le_advertising_manager.h"
+#include "hci/le_scanning_manager.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "neighbor/connectability.h"
+#include "neighbor/discoverability.h"
+#include "neighbor/inquiry.h"
+#include "neighbor/name.h"
+#include "neighbor/page.h"
+#include "neighbor/scan.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "security/security_module.h"
+#include "shim/advertising.h"
+#include "shim/connectability.h"
+#include "shim/controller.h"
+#include "shim/discoverability.h"
+#include "shim/hci_layer.h"
+#include "shim/inquiry.h"
+#include "shim/l2cap.h"
+#include "shim/name.h"
+#include "shim/page.h"
+#include "shim/scanning.h"
+#include "stack_manager.h"
+
+using ::bluetooth::os::Thread;
+
+struct bluetooth::shim::Stack::impl {
+  void Start() {
+    if (is_running_) {
+      LOG_ERROR("%s Gd stack already running", __func__);
+      return;
+    }
+
+    LOG_INFO("%s Starting Gd stack", __func__);
+    ModuleList modules;
+    modules.add<::bluetooth::hal::HciHal>();
+    modules.add<::bluetooth::hci::AclManager>();
+    modules.add<::bluetooth::hci::LeAdvertisingManager>();
+    modules.add<::bluetooth::hci::LeScanningManager>();
+    modules.add<::bluetooth::l2cap::classic::L2capClassicModule>();
+    modules.add<::bluetooth::l2cap::le::L2capLeModule>();
+    modules.add<::bluetooth::neighbor::ConnectabilityModule>();
+    modules.add<::bluetooth::neighbor::DiscoverabilityModule>();
+    modules.add<::bluetooth::neighbor::InquiryModule>();
+    modules.add<::bluetooth::neighbor::NameModule>();
+    modules.add<::bluetooth::neighbor::PageModule>();
+    modules.add<::bluetooth::neighbor::ScanModule>();
+    modules.add<::bluetooth::shim::Controller>();
+    modules.add<::bluetooth::shim::HciLayer>();
+    modules.add<::bluetooth::security::SecurityModule>();
+    modules.add<::bluetooth::shim::Advertising>();
+    modules.add<::bluetooth::shim::Connectability>();
+    modules.add<::bluetooth::shim::Discoverability>();
+    modules.add<::bluetooth::shim::Inquiry>();
+    modules.add<::bluetooth::shim::Name>();
+    modules.add<::bluetooth::shim::L2cap>();
+    modules.add<::bluetooth::shim::Page>();
+    modules.add<::bluetooth::shim::Scanning>();
+
+    stack_thread_ = new Thread("gd_stack_thread", Thread::Priority::NORMAL);
+    stack_manager_.StartUp(&modules, stack_thread_);
+    // TODO(cmanton) Gd stack has spun up another thread with no
+    // ability to ascertain the completion
+    is_running_ = true;
+    LOG_INFO("%s Successfully toggled Gd stack", __func__);
+  }
+
+  void Stop() {
+    if (!is_running_) {
+      LOG_ERROR("%s Gd stack not running", __func__);
+      return;
+    }
+
+    stack_manager_.ShutDown();
+    delete stack_thread_;
+    is_running_ = false;
+    LOG_INFO("%s Successfully shut down Gd stack", __func__);
+  }
+
+  IAdvertising* GetAdvertising() {
+    return stack_manager_.GetInstance<bluetooth::shim::Advertising>();
+  }
+
+  IController* GetController() {
+    return stack_manager_.GetInstance<bluetooth::shim::Controller>();
+  }
+
+  IConnectability* GetConnectability() {
+    return stack_manager_.GetInstance<bluetooth::shim::Connectability>();
+  }
+
+  IDiscoverability* GetDiscoverability() {
+    return stack_manager_.GetInstance<bluetooth::shim::Discoverability>();
+  }
+
+  IHciLayer* GetHciLayer() {
+    return stack_manager_.GetInstance<bluetooth::shim::HciLayer>();
+  }
+
+  IInquiry* GetInquiry() {
+    return stack_manager_.GetInstance<bluetooth::shim::Inquiry>();
+  }
+
+  IL2cap* GetL2cap() {
+    return stack_manager_.GetInstance<bluetooth::shim::L2cap>();
+  }
+
+  IName* GetName() {
+    return stack_manager_.GetInstance<bluetooth::shim::Name>();
+  }
+
+  IPage* GetPage() {
+    return stack_manager_.GetInstance<bluetooth::shim::Page>();
+  }
+
+  IScanning* GetScanning() {
+    return stack_manager_.GetInstance<bluetooth::shim::Scanning>();
+  }
+
+ private:
+  os::Thread* stack_thread_ = nullptr;
+  bool is_running_ = false;
+  StackManager stack_manager_;
+};
+
+bluetooth::shim::Stack::Stack() {
+  pimpl_ = std::make_unique<impl>();
+  LOG_INFO("%s Created gd stack", __func__);
+}
+
+void bluetooth::shim::Stack::Start() {
+  pimpl_->Start();
+}
+
+void bluetooth::shim::Stack::Stop() {
+  pimpl_->Stop();
+}
+
+bluetooth::shim::IAdvertising* bluetooth::shim::Stack::GetAdvertising() {
+  return pimpl_->GetAdvertising();
+}
+
+bluetooth::shim::IConnectability* bluetooth::shim::Stack::GetConnectability() {
+  return pimpl_->GetConnectability();
+}
+
+bluetooth::shim::IController* bluetooth::shim::Stack::GetController() {
+  return pimpl_->GetController();
+}
+
+bluetooth::shim::IDiscoverability* bluetooth::shim::Stack::GetDiscoverability() {
+  return pimpl_->GetDiscoverability();
+}
+
+bluetooth::shim::IHciLayer* bluetooth::shim::Stack::GetHciLayer() {
+  return pimpl_->GetHciLayer();
+}
+
+bluetooth::shim::IInquiry* bluetooth::shim::Stack::GetInquiry() {
+  return pimpl_->GetInquiry();
+}
+
+bluetooth::shim::IL2cap* bluetooth::shim::Stack::GetL2cap() {
+  return pimpl_->GetL2cap();
+}
+
+bluetooth::shim::IName* bluetooth::shim::Stack::GetName() {
+  return pimpl_->GetName();
+}
+
+bluetooth::shim::IPage* bluetooth::shim::Stack::GetPage() {
+  return pimpl_->GetPage();
+}
+
+bluetooth::shim::IScanning* bluetooth::shim::Stack::GetScanning() {
+  return pimpl_->GetScanning();
+}
+
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+  static IStack* instance = new Stack();
+  return instance;
+}
diff --git a/gd/shim/stack.h b/gd/shim/stack.h
new file mode 100644
index 0000000..f4a51fc
--- /dev/null
+++ b/gd/shim/stack.h
@@ -0,0 +1,67 @@
+/*
+ * 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 <memory>
+
+#include "shim/iadvertising.h"
+#include "shim/iconnectability.h"
+#include "shim/icontroller.h"
+#include "shim/idiscoverability.h"
+#include "shim/ihci_layer.h"
+#include "shim/iinquiry.h"
+#include "shim/il2cap.h"
+#include "shim/iname.h"
+#include "shim/ipage.h"
+#include "shim/iscanning.h"
+#include "shim/istack.h"
+
+/**
+ * The shim layer implementation on the Gd stack side.
+ */
+namespace bluetooth {
+namespace shim {
+
+class Stack : public IStack {
+ public:
+  Stack();
+  ~Stack() = default;
+
+  void Start() override;  // IStack
+  void Stop() override;   // IStack
+
+  IAdvertising* GetAdvertising() override;  // IStack
+  IController* GetController() override;  // IStack
+  IConnectability* GetConnectability() override;  // IStack
+  IHciLayer* GetHciLayer() override;      // IStack
+  IDiscoverability* GetDiscoverability() override;  // IStack
+  IInquiry* GetInquiry() override;                  // IStack
+  IName* GetName() override;                        // IStack
+  IL2cap* GetL2cap() override;                      // IStack
+  IPage* GetPage() override;                        // IStack
+  IScanning* GetScanning() override;                // IStack
+
+ private:
+  struct impl;
+  std::unique_ptr<impl> pimpl_;
+
+  Stack(const Stack&) = delete;
+  void operator=(const Stack&) = delete;
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/smp/Android.bp b/gd/smp/Android.bp
deleted file mode 100644
index b67878f..0000000
--- a/gd/smp/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-filegroup {
-    name: "BluetoothSmpSources",
-    srcs: [
-        "ecc/multprecision.cc",
-        "ecc/p_256_ecc_pp.cc",
-    ]
-}
-
-filegroup {
-    name: "BluetoothSmpTestSources",
-    srcs: [
-        "ecc/multipoint_test.cc",
-    ]
-}
\ No newline at end of file
diff --git a/hci/Android.bp b/hci/Android.bp
index 635d939..ddfef50 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -3,9 +3,8 @@
     defaults: ["fluoride_defaults"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
     ],
 }
 
diff --git a/hci/include/bt_hci_bdroid.h b/hci/include/bt_hci_bdroid.h
index cf2c113..110354f 100644
--- a/hci/include/bt_hci_bdroid.h
+++ b/hci/include/bt_hci_bdroid.h
@@ -53,15 +53,17 @@
 #define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
 
 /* Message event ID passed from Host/Controller lib to stack */
-#define MSG_HC_TO_STACK_HCI_ERR 0x1300      /* eq. BT_EVT_TO_BTU_HCIT_ERR */
 #define MSG_HC_TO_STACK_HCI_ACL 0x1100      /* eq. BT_EVT_TO_BTU_HCI_ACL */
 #define MSG_HC_TO_STACK_HCI_SCO 0x1200      /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300      /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ISO 0x1700      /* eq. BT_EVT_TO_BTU_HCI_ISO */
 #define MSG_HC_TO_STACK_HCI_EVT 0x1000      /* eq. BT_EVT_TO_BTU_HCI_EVT */
 #define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
 
 /* Message event ID passed from stack to vendor lib */
 #define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
 #define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */
 #define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
 
 /* Local Bluetooth Controller ID for BR/EDR */
diff --git a/hci/include/btsnoop.h b/hci/include/btsnoop.h
index e897a96..476c62d 100644
--- a/hci/include/btsnoop.h
+++ b/hci/include/btsnoop.h
@@ -29,6 +29,28 @@
   // true, the packet is marked as incoming. Otherwise, the packet is marked
   // as outgoing.
   void (*capture)(const BT_HDR* packet, bool is_received);
+
+  // Set a L2CAP channel as whitelisted, allowing packets with that L2CAP CID
+  // to show up in the snoop logs.
+  void (*whitelist_l2c_channel)(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid);
+
+  // Set a RFCOMM dlci as whitelisted, allowing packets with that RFCOMM CID
+  // to show up in the snoop logs. The local_cid is used to associate it with
+  // its corrisponding ACL connection. The dlci is the channel with direction
+  // so there is no chance of a collision if two services are using the same
+  // channel but in different directions.
+  void (*whitelist_rfc_dlci)(uint16_t local_cid, uint8_t dlci);
+
+  // Indicate that the provided L2CAP channel is being used for RFCOMM.
+  // If packets with the provided L2CAP CID are encountered, they will be
+  // filtered on RFCOMM based on channels provided to |filter_rfc_channel|.
+  void (*add_rfc_l2c_channel)(uint16_t conn_handle, uint16_t local_cid,
+                              uint16_t remote_cid);
+
+  // Clear an L2CAP channel from being filtered.
+  void (*clear_l2cap_whitelist)(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid);
 } btsnoop_t;
 
 const btsnoop_t* btsnoop_get_interface(void);
diff --git a/hci/include/hci_hal.h b/hci/include/hci_hal.h
index f73e116..6fbb13e 100644
--- a/hci/include/hci_hal.h
+++ b/hci/include/hci_hal.h
@@ -29,7 +29,8 @@
   DATA_TYPE_COMMAND = 1,
   DATA_TYPE_ACL = 2,
   DATA_TYPE_SCO = 3,
-  DATA_TYPE_EVENT = 4
+  DATA_TYPE_EVENT = 4,
+  DATA_TYPE_ISO = 5
 } serial_data_type_t;
 
 typedef void (*data_ready_cb)(serial_data_type_t type);
diff --git a/hci/include/hci_internals.h b/hci/include/hci_internals.h
index 8fe0041..bf9430f 100644
--- a/hci/include/hci_internals.h
+++ b/hci/include/hci_internals.h
@@ -26,3 +26,5 @@
 #define HCI_SCO_PREAMBLE_SIZE 3
 // 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
 #define HCI_EVENT_PREAMBLE_SIZE 2
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.5)
+#define HCI_ISO_PREAMBLE_SIZE 4
\ No newline at end of file
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index 5eb2bd5..bf4efee 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -37,15 +37,17 @@
 #define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
 
 /* Message event ID passed from Host/Controller lib to stack */
-#define MSG_HC_TO_STACK_HCI_ERR 0x1300      /* eq. BT_EVT_TO_BTU_HCIT_ERR */
 #define MSG_HC_TO_STACK_HCI_ACL 0x1100      /* eq. BT_EVT_TO_BTU_HCI_ACL */
 #define MSG_HC_TO_STACK_HCI_SCO 0x1200      /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300      /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ISO 0x1700      /* eq. BT_EVT_TO_BTU_HCI_ISO */
 #define MSG_HC_TO_STACK_HCI_EVT 0x1000      /* eq. BT_EVT_TO_BTU_HCI_EVT */
 #define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
 
 /* Message event ID passed from stack to vendor lib */
 #define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
 #define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */
 #define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
 
 /* Local Bluetooth Controller ID for BR/EDR */
@@ -83,6 +85,11 @@
   void (*transmit_downward)(uint16_t type, void* data);
 } hci_t;
 
+namespace bluetooth {
+namespace legacy {
+const hci_t* hci_layer_get_interface();
+}  // namespace legacy
+}  // namespace bluetooth
 const hci_t* hci_layer_get_interface();
 
 const hci_t* hci_layer_get_test_interface(
diff --git a/hci/src/btsnoop.cc b/hci/src/btsnoop.cc
index 6938725..ad06ac7 100644
--- a/hci/src/btsnoop.cc
+++ b/hci/src/btsnoop.cc
@@ -21,6 +21,7 @@
 #include <mutex>
 
 #include <arpa/inet.h>
+#include <base/logging.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -34,14 +35,21 @@
 #include <sys/time.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
 
 #include "bt_types.h"
 #include "common/time_util.h"
 #include "hci/include/btsnoop.h"
 #include "hci/include/btsnoop_mem.h"
 #include "hci_layer.h"
+#include "internal_include/bt_trace.h"
 #include "osi/include/log.h"
 #include "osi/include/properties.h"
+#include "stack/include/hcimsgs.h"
+#include "stack/include/rfcdefs.h"
+#include "stack/l2cap/l2c_int.h"
 #include "stack_config.h"
 
 // The number of of packets per btsnoop file before we rotate to the next
@@ -50,7 +58,14 @@
 // property
 #define DEFAULT_BTSNOOP_SIZE 0xffff
 
-#define BTSNOOP_ENABLE_PROPERTY "persist.bluetooth.btsnoopenable"
+#define IS_DEBUGGABLE_PROPERTY "ro.debuggable"
+
+#define BTSNOOP_LOG_MODE_PROPERTY "persist.bluetooth.btsnooplogmode"
+#define BTSNOOP_DEFAULT_MODE_PROPERTY "persist.bluetooth.btsnoopdefaultmode"
+#define BTSNOOP_MODE_DISABLED "disabled"
+#define BTSNOOP_MODE_FILTERED "filtered"
+#define BTSNOOP_MODE_FULL "full"
+
 #define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath"
 #define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log"
 #define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize"
@@ -65,33 +80,138 @@
 // Epoch in microseconds since 01/01/0000.
 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
 
+// Number of bytes into a packet where you can find the value for a channel.
+static const size_t ACL_CHANNEL_OFFSET = 0;
+static const size_t L2C_CHANNEL_OFFSET = 6;
+static const size_t RFC_CHANNEL_OFFSET = 8;
+static const size_t RFC_EVENT_OFFSET = 9;
+
+// The size of the L2CAP header. All information past this point is removed from
+// a filtered packet.
+static const uint32_t L2C_HEADER_SIZE = 9;
+
 static int logfile_fd = INVALID_FD;
 static std::mutex btsnoop_mutex;
 
 static int32_t packets_per_file;
 static int32_t packet_counter;
 
+// Channel tracking variables for filtering.
+
+// Keeps track of L2CAP channels that need to be filtered out of the snoop
+// logs.
+class FilterTracker {
+ public:
+  // NOTE: 1 is used as a static CID for L2CAP signaling
+  std::unordered_set<uint16_t> l2c_local_cid = {1};
+  std::unordered_set<uint16_t> l2c_remote_cid = {1};
+  uint16_t rfc_local_cid = 0;
+  uint16_t rfc_remote_cid = 0;
+  std::unordered_set<uint16_t> rfc_channels = {0};
+
+  // Adds L2C channel to whitelist.
+  void addL2cCid(uint16_t local_cid, uint16_t remote_cid) {
+    l2c_local_cid.insert(local_cid);
+    l2c_remote_cid.insert(remote_cid);
+  }
+
+  // Sets L2CAP channel that RFCOMM uses.
+  void setRfcCid(uint16_t local_cid, uint16_t remote_cid) {
+    rfc_local_cid = local_cid;
+    rfc_remote_cid = remote_cid;
+  }
+
+  // Remove L2C channel from whitelist.
+  void removeL2cCid(uint16_t local_cid, uint16_t remote_cid) {
+    if (rfc_local_cid == local_cid) {
+      rfc_channels.clear();
+      rfc_channels.insert(0);
+      rfc_local_cid = 0;
+      rfc_remote_cid = 0;
+    }
+
+    l2c_local_cid.erase(local_cid);
+    l2c_remote_cid.erase(remote_cid);
+  }
+
+  void addRfcDlci(uint8_t channel) { rfc_channels.insert(channel); }
+
+  bool isWhitelistedL2c(bool local, uint16_t cid) {
+    const auto& set = local ? l2c_local_cid : l2c_remote_cid;
+    return (set.find(cid) != set.end());
+  }
+
+  bool isRfcChannel(bool local, uint16_t cid) {
+    const auto& channel = local ? rfc_local_cid : rfc_remote_cid;
+    return cid == channel;
+  }
+
+  bool isWhitelistedDlci(uint8_t dlci) {
+    return rfc_channels.find(dlci) != rfc_channels.end();
+  }
+};
+
+std::mutex filter_list_mutex;
+std::unordered_map<uint16_t, FilterTracker> filter_list;
+std::unordered_map<uint16_t, uint16_t> local_cid_to_acl;
+
+// Cached value for whether full snoop logs are enabled. So the property isn't
+// checked for every packet.
+static bool is_btsnoop_enabled;
+static bool is_btsnoop_filtered;
+
 // TODO(zachoverflow): merge btsnoop and btsnoop_net together
 void btsnoop_net_open();
 void btsnoop_net_close();
 void btsnoop_net_write(const void* data, size_t length);
 
-static void delete_btsnoop_files();
-static bool is_btsnoop_enabled();
-static char* get_btsnoop_log_path(char* log_path);
-static char* get_btsnoop_last_log_path(char* last_log_path, char* log_path);
+static void delete_btsnoop_files(bool filtered);
+static std::string get_btsnoop_log_path(bool filtered);
+static std::string get_btsnoop_last_log_path(std::string log_path);
 static void open_next_snoop_file();
 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
                                  bool is_received, uint64_t timestamp_us);
 
 // Module lifecycle functions
 
-static future_t* start_up(void) {
+static future_t* start_up() {
+  std::array<char, PROPERTY_VALUE_MAX> property = {};
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
 
-  if (!is_btsnoop_enabled()) {
-    delete_btsnoop_files();
+  // Default mode is FILTERED on userdebug/eng build, DISABLED on user build.
+  // It can also be overwritten by modifying the global setting.
+  int is_debuggable = osi_property_get_int32(IS_DEBUGGABLE_PROPERTY, 0);
+  std::string default_mode = BTSNOOP_MODE_DISABLED;
+  if (is_debuggable) {
+    int len = osi_property_get(BTSNOOP_DEFAULT_MODE_PROPERTY, property.data(),
+                               BTSNOOP_MODE_DISABLED);
+    default_mode = std::string(property.data(), len);
+  }
+
+  // Get the actual mode
+  int len = osi_property_get(BTSNOOP_LOG_MODE_PROPERTY, property.data(),
+                             default_mode.c_str());
+  std::string btsnoop_mode(property.data(), len);
+
+  if (btsnoop_mode == BTSNOOP_MODE_FILTERED) {
+    LOG(INFO) << __func__ << ": Filtered Snoop Logs enabled";
+    is_btsnoop_enabled = true;
+    is_btsnoop_filtered = true;
+    delete_btsnoop_files(false);
+  } else if (btsnoop_mode == BTSNOOP_MODE_FULL) {
+    LOG(INFO) << __func__ << ": Snoop Logs fully enabled";
+    is_btsnoop_enabled = true;
+    is_btsnoop_filtered = false;
+    delete_btsnoop_files(true);
   } else {
+    LOG(INFO) << __func__ << ": Snoop Logs disabled";
+    is_btsnoop_enabled = false;
+    is_btsnoop_filtered = false;
+    delete_btsnoop_files(true);
+    delete_btsnoop_files(false);
+  }
+
+  if (is_btsnoop_enabled) {
     open_next_snoop_file();
     packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY,
                                               DEFAULT_BTSNOOP_SIZE);
@@ -104,14 +224,21 @@
 static future_t* shut_down(void) {
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
 
-  if (!is_btsnoop_enabled()) {
-    delete_btsnoop_files();
+  if (is_btsnoop_enabled) {
+    if (is_btsnoop_filtered) {
+      delete_btsnoop_files(false);
+    } else {
+      delete_btsnoop_files(true);
+    }
+  } else {
+    delete_btsnoop_files(true);
+    delete_btsnoop_files(false);
   }
 
   if (logfile_fd != INVALID_FD) close(logfile_fd);
   logfile_fd = INVALID_FD;
 
-  btsnoop_net_close();
+  if (is_btsnoop_enabled) btsnoop_net_close();
 
   return NULL;
 }
@@ -129,7 +256,12 @@
   uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
 
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
-  uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
+
+  struct timespec ts_now = {};
+  clock_gettime(CLOCK_REALTIME, &ts_now);
+  uint64_t timestamp_us =
+      ((uint64_t)ts_now.tv_sec * 1000000L) + ((uint64_t)ts_now.tv_nsec / 1000);
+
   btsnoop_mem_capture(buffer, timestamp_us);
 
   if (logfile_fd == INVALID_FD) return;
@@ -152,39 +284,75 @@
   }
 }
 
-static const btsnoop_t interface = {capture};
+static void whitelist_l2c_channel(uint16_t conn_handle, uint16_t local_cid,
+                                  uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": Whitelisting l2cap channel. conn_handle=" << conn_handle
+            << " cid=" << loghex(local_cid) << ":" << loghex(remote_cid);
+  std::lock_guard lock(filter_list_mutex);
 
-const btsnoop_t* btsnoop_get_interface() {
-  return &interface;
+  // This will create the entry if there is no associated filter with the
+  // connection.
+  filter_list[conn_handle].addL2cCid(local_cid, remote_cid);
 }
 
-// Internal functions
-static void delete_btsnoop_files() {
-  LOG_VERBOSE(LOG_TAG, "Deleting snoop log if it exists");
-  char log_path[PROPERTY_VALUE_MAX];
-  char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
-  get_btsnoop_log_path(log_path);
-  get_btsnoop_last_log_path(last_log_path, log_path);
-  remove(log_path);
-  remove(last_log_path);
+static void whitelist_rfc_dlci(uint16_t local_cid, uint8_t dlci) {
+  LOG(INFO) << __func__
+            << ": Whitelisting rfcomm channel. L2CAP CID=" << loghex(local_cid)
+            << " DLCI=" << loghex(dlci);
+  std::lock_guard lock(filter_list_mutex);
+
+  tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, local_cid);
+  filter_list[p_ccb->p_lcb->handle].addRfcDlci(dlci);
 }
 
-static bool is_btsnoop_enabled() {
-  char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0};
-  osi_property_get(BTSNOOP_ENABLE_PROPERTY, btsnoop_enabled, "false");
-  return strncmp(btsnoop_enabled, "true", 4) == 0;
+static void add_rfc_l2c_channel(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": rfcomm data going over l2cap channel. conn_handle="
+            << conn_handle << " cid=" << loghex(local_cid) << ":"
+            << loghex(remote_cid);
+  std::lock_guard lock(filter_list_mutex);
+
+  filter_list[conn_handle].setRfcCid(local_cid, remote_cid);
+  local_cid_to_acl.insert({local_cid, conn_handle});
 }
 
-static char* get_btsnoop_log_path(char* btsnoop_path) {
+static void clear_l2cap_whitelist(uint16_t conn_handle, uint16_t local_cid,
+                                  uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": Clearing whitelist from l2cap channel. conn_handle="
+            << conn_handle << " cid=" << local_cid << ":" << remote_cid;
+
+  std::lock_guard lock(filter_list_mutex);
+  filter_list[conn_handle].removeL2cCid(local_cid, remote_cid);
+}
+
+static const btsnoop_t interface = {capture, whitelist_l2c_channel,
+                                    whitelist_rfc_dlci, add_rfc_l2c_channel,
+                                    clear_l2cap_whitelist};
+
+const btsnoop_t* btsnoop_get_interface() { return &interface; }
+
+static void delete_btsnoop_files(bool filtered) {
+  LOG(INFO) << __func__
+            << ": Deleting snoop logs if they exist. filtered = " << filtered;
+  auto log_path = get_btsnoop_log_path(filtered);
+  remove(log_path.c_str());
+  remove(get_btsnoop_last_log_path(log_path).c_str());
+}
+
+std::string get_btsnoop_log_path(bool filtered) {
+  char btsnoop_path[PROPERTY_VALUE_MAX];
   osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH);
-  return btsnoop_path;
+  std::string result(btsnoop_path);
+  if (filtered) result = result.append(".filtered");
+
+  return result;
 }
 
-static char* get_btsnoop_last_log_path(char* last_log_path,
-                                       char* btsnoop_path) {
-  snprintf(last_log_path, PROPERTY_VALUE_MAX + sizeof(".last"), "%s.last",
-           btsnoop_path);
-  return last_log_path;
+std::string get_btsnoop_last_log_path(std::string btsnoop_path) {
+  return btsnoop_path.append(".last");
 }
 
 static void open_next_snoop_file() {
@@ -195,22 +363,20 @@
     logfile_fd = INVALID_FD;
   }
 
-  char log_path[PROPERTY_VALUE_MAX];
-  char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
-  get_btsnoop_log_path(log_path);
-  get_btsnoop_last_log_path(last_log_path, log_path);
+  auto log_path = get_btsnoop_log_path(is_btsnoop_filtered);
+  auto last_log_path = get_btsnoop_last_log_path(log_path);
 
-  if (rename(log_path, last_log_path) != 0 && errno != ENOENT)
-    LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
-              log_path, last_log_path, strerror(errno));
+  if (rename(log_path.c_str(), last_log_path.c_str()) != 0 && errno != ENOENT)
+    LOG(ERROR) << __func__ << ": unable to rename '" << log_path << "' to '"
+               << last_log_path << "' : " << strerror(errno);
 
   mode_t prevmask = umask(0);
-  logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
+  logfile_fd = open(log_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
   umask(prevmask);
   if (logfile_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
-              strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to open '" << log_path
+               << "' : " << strerror(errno);
     return;
   }
 
@@ -235,6 +401,32 @@
   return ll;
 }
 
+static bool should_filter_log(bool is_received, uint8_t* packet) {
+  uint16_t acl_handle =
+      HCID_GET_HANDLE((((uint16_t)packet[ACL_CHANNEL_OFFSET + 1]) << 8) +
+                      packet[ACL_CHANNEL_OFFSET]);
+
+  std::lock_guard lock(filter_list_mutex);
+  auto& filters = filter_list[acl_handle];
+  uint16_t l2c_channel =
+      (packet[L2C_CHANNEL_OFFSET + 1] << 8) + packet[L2C_CHANNEL_OFFSET];
+  if (filters.isRfcChannel(is_received, l2c_channel)) {
+    uint8_t rfc_event = packet[RFC_EVENT_OFFSET] & 0b11101111;
+    if (rfc_event == RFCOMM_SABME || rfc_event == RFCOMM_UA) {
+      return false;
+    }
+
+    uint8_t rfc_dlci = packet[RFC_CHANNEL_OFFSET] >> 2;
+    if (!filters.isWhitelistedDlci(rfc_dlci)) {
+      return true;
+    }
+  } else if (!filters.isWhitelistedL2c(is_received, l2c_channel)) {
+    return true;
+  }
+
+  return false;
+}
+
 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
                                  bool is_received, uint64_t timestamp_us) {
   uint32_t length_he = 0;
@@ -261,7 +453,15 @@
 
   btsnoop_header_t header;
   header.length_original = htonl(length_he);
-  header.length_captured = header.length_original;
+
+  bool blacklisted = false;
+  if (is_btsnoop_filtered && type == kAclPacket) {
+    blacklisted = should_filter_log(is_received, packet);
+  }
+
+  header.length_captured =
+      blacklisted ? htonl(L2C_HEADER_SIZE) : header.length_original;
+  if (blacklisted) length_he = L2C_HEADER_SIZE;
   header.flags = htonl(flags);
   header.dropped_packets = 0;
   header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA);
diff --git a/hci/src/hci_inject.cc b/hci/src/hci_inject.cc
index 01b8cfd..6d3e8e0 100644
--- a/hci/src/hci_inject.cc
+++ b/hci/src/hci_inject.cc
@@ -39,6 +39,7 @@
   HCI_PACKET_ACL_DATA = 2,
   HCI_PACKET_SCO_DATA = 3,
   HCI_PACKET_EVENT = 4,
+  HCI_PACKET_ISO_DATA = 5,
 } hci_packet_t;
 
 typedef struct {
@@ -118,6 +119,8 @@
       return MSG_STACK_TO_HC_HCI_ACL;
     case HCI_PACKET_SCO_DATA:
       return MSG_STACK_TO_HC_HCI_SCO;
+    case HCI_PACKET_ISO_DATA:
+      return MSG_STACK_TO_HC_HCI_ISO;
     default:
       LOG_ERROR(LOG_TAG, "%s unsupported packet type: %d", __func__, packet);
       return -1;
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index ed2908c..da6054b 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -44,6 +44,7 @@
 #include "hci_internals.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
+#include "main/shim/shim.h"
 #include "osi/include/alarm.h"
 #include "osi/include/list.h"
 #include "osi/include/log.h"
@@ -160,6 +161,11 @@
   packet_fragmenter->reassemble_and_dispatch(packet);
 }
 
+void iso_data_received(BT_HDR* packet) {
+  btsnoop->capture(packet, true);
+  packet_fragmenter->reassemble_and_dispatch(packet);
+}
+
 // Module lifecycle functions
 
 static future_t* hci_module_shut_down();
@@ -510,8 +516,7 @@
 
   uint8_t* hci_packet = reinterpret_cast<uint8_t*>(bt_hdr + 1);
 
-  UINT16_TO_STREAM(hci_packet,
-                   HCI_GRP_VENDOR_SPECIFIC | HCI_CONTROLLER_DEBUG_INFO_OCF);
+  UINT16_TO_STREAM(hci_packet, HCI_CONTROLLER_DEBUG_INFO);
   UINT8_TO_STREAM(hci_packet, 0);  // No parameters
 
   hci_firmware_log_fd = hci_open_firmware_log_file();
@@ -720,7 +725,21 @@
   }
 }
 
+namespace bluetooth {
+namespace shim {
+const hci_t* hci_layer_get_interface();
+}  // namespace shim
+}  // namespace bluetooth
+
 const hci_t* hci_layer_get_interface() {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::hci_layer_get_interface();
+  } else {
+    return bluetooth::legacy::hci_layer_get_interface();
+  }
+}
+
+const hci_t* bluetooth::legacy::hci_layer_get_interface() {
   buffer_allocator = buffer_allocator_get_interface();
   btsnoop = btsnoop_get_interface();
   packet_fragmenter = packet_fragmenter_get_interface();
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index d3fa526..c4aded1 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -32,6 +32,8 @@
 #include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
 #include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
 #include <android/hardware/bluetooth/1.0/types.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
 #include <hwbinder/ProcessState.h>
 
 #define LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log"
@@ -43,16 +45,18 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::bluetooth::V1_0::HciPacket;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
 using ::android::hardware::bluetooth::V1_0::Status;
 
+using namespace ::android::hardware::bluetooth;
+
 extern void initialization_complete();
 extern void hci_event_received(const base::Location& from_here, BT_HDR* packet);
 extern void acl_event_received(BT_HDR* packet);
 extern void sco_data_received(BT_HDR* packet);
+extern void iso_data_received(BT_HDR* packet);
 
-android::sp<IBluetoothHci> btHci;
+android::sp<V1_0::IBluetoothHci> btHci;
+android::sp<V1_1::IBluetoothHci> btHci_1_1;
 
 class BluetoothHciDeathRecipient : public hidl_death_recipient {
  public:
@@ -63,7 +67,7 @@
 };
 android::sp<BluetoothHciDeathRecipient> bluetoothHciDeathRecipient = new BluetoothHciDeathRecipient();
 
-class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
+class BluetoothHciCallbacks : public V1_1::IBluetoothHciCallbacks {
  public:
   BluetoothHciCallbacks() {
     buffer_allocator = buffer_allocator_get_interface();
@@ -107,13 +111,26 @@
     return Void();
   }
 
+  Return<void> isoDataReceived(const hidl_vec<uint8_t>& data) override {
+    BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, data);
+    iso_data_received(packet);
+    return Void();
+  }
+
   const allocator_t* buffer_allocator;
 };
 
 void hci_initialize() {
   LOG_INFO(LOG_TAG, "%s", __func__);
 
-  btHci = IBluetoothHci::getService();
+  btHci_1_1 = V1_1::IBluetoothHci::getService();
+
+  if (btHci_1_1 != nullptr) {
+    btHci = btHci_1_1;
+  } else {
+    btHci = V1_0::IBluetoothHci::getService();
+  }
+
   // If android.hardware.bluetooth* is not found, Bluetooth can not continue.
   CHECK(btHci != nullptr);
   auto death_link = btHci->linkToDeath(bluetoothHciDeathRecipient, 0);
@@ -126,8 +143,13 @@
 
   // Block allows allocation of a variable that might be bypassed by goto.
   {
-    android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
-    btHci->initialize(callbacks);
+    android::sp<V1_1::IBluetoothHciCallbacks> callbacks =
+        new BluetoothHciCallbacks();
+    if (btHci_1_1 != nullptr) {
+      btHci_1_1->initialize(callbacks);
+    } else {
+      btHci->initialize(callbacks);
+    }
   }
 }
 
@@ -157,6 +179,13 @@
     case MSG_STACK_TO_HC_HCI_SCO:
       btHci->sendScoData(data);
       break;
+    case MSG_STACK_TO_HC_HCI_ISO:
+      if (btHci_1_1 != nullptr) {
+        btHci_1_1->sendIsoData(data);
+      } else {
+        LOG_ERROR(LOG_TAG, "ISO is not supported in HAL v1.0");
+      }
+      break;
     default:
       LOG_ERROR(LOG_TAG, "Unknown packet type (%d)", event);
       break;
diff --git a/hci/src/packet_fragmenter.cc b/hci/src/packet_fragmenter.cc
index c1c61df..f688982 100644
--- a/hci/src/packet_fragmenter.cc
+++ b/hci/src/packet_fragmenter.cc
@@ -123,12 +123,10 @@
   if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
     uint8_t* stream = packet->data;
     uint16_t handle;
-    uint16_t l2cap_length;
     uint16_t acl_length;
 
     STREAM_TO_UINT16(handle, stream);
     STREAM_TO_UINT16(acl_length, stream);
-    STREAM_TO_UINT16(l2cap_length, stream);
 
     CHECK(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
 
@@ -136,6 +134,13 @@
     handle = handle & HANDLE_MASK;
 
     if (boundary_flag == START_PACKET_BOUNDARY) {
+      if (acl_length < 2) {
+        LOG_WARN(LOG_TAG, "%s invalid acl_length %d", __func__, acl_length);
+        buffer_allocator->free(packet);
+        return;
+      }
+      uint16_t l2cap_length;
+      STREAM_TO_UINT16(l2cap_length, stream);
       auto map_iter = partial_packets.find(handle);
       if (map_iter != partial_packets.end()) {
         LOG_WARN(LOG_TAG,
diff --git a/include/hardware/bluetooth.h b/include/hardware/bluetooth.h
index f97e116..063abf9 100644
--- a/include/hardware/bluetooth.h
+++ b/include/hardware/bluetooth.h
@@ -466,11 +466,16 @@
   /**
    * Opens the interface and provides the callback routines
    * to the implemenation of this interface.
+   * The |start_restricted| flag inits the adapter in restricted mode. In
+   * restricted mode, bonds that are created are marked as restricted in the
+   * config file. These devices are deleted upon leaving restricted mode.
+   * The |is_single_user_mode| flag inits the adapter in NIAP mode.
    */
-  int (*init)(bt_callbacks_t* callbacks);
+  int (*init)(bt_callbacks_t* callbacks, bool guest_mode,
+              bool is_single_user_mode);
 
   /** Enable Bluetooth. */
-  int (*enable)(bool guest_mode);
+  int (*enable)();
 
   /** Disable Bluetooth. */
   int (*disable)(void);
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index 67a67c5..1356d2e 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -108,7 +108,7 @@
 #endif
 
 #ifndef BTA_DM_SDP_DB_SIZE
-#define BTA_DM_SDP_DB_SIZE 8000
+#define BTA_DM_SDP_DB_SIZE 20000
 #endif
 
 #ifndef HL_INCLUDED
@@ -534,7 +534,7 @@
 
 /* Whether link wants to be the master or the slave. */
 #ifndef L2CAP_DESIRED_LINK_ROLE
-#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_MASTER
 #endif
 
 /* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
diff --git a/main/Android.bp b/main/Android.bp
index 3efd993..ef7dba6 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,18 +1,32 @@
 // Bluetooth main HW module / shared library for target
 // ========================================================
+filegroup {
+    name: "LibBluetoothSources",
+    srcs: [
+        "bte_conf.cc",
+        "bte_init.cc",
+        "bte_init_cpp_logging.cc",
+        "bte_logmsg.cc",
+        "bte_main.cc",
+        "shim/btm.cc",
+        "shim/btm_api.cc",
+        "shim/controller.cc",
+        "shim/entry.cc",
+        "shim/hci_layer.cc",
+        "shim/l2c_api.cc",
+        "shim/l2cap.cc",
+        "shim/shim.cc",
+        "stack_config.cc",
+    ]
+}
+
 cc_library_shared {
     name: "libbluetooth",
     defaults: ["fluoride_defaults"],
     header_libs: ["libbluetooth_headers"],
     export_header_lib_headers: ["libbluetooth_headers"],
     srcs: [
-        // platform specific
-        "bte_conf.cc",
-        "bte_init.cc",
-        "bte_init_cpp_logging.cc",
-        "bte_logmsg.cc",
-        "bte_main.cc",
-        "stack_config.cc",
+        ":LibBluetoothSources",
     ],
     include_dirs: [
         "system/bt",
@@ -34,10 +48,13 @@
         "system/bt/embdrv/sbc/encoder/include",
         "system/bt/embdrv/sbc/decoder/include",
         "system/bt/utils/include",
+        "system/security/keystore/include",
+        "hardware/interfaces/keymaster/4.0/support/include",
     ],
     logtags: ["../EventLogTags.logtags"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "android.hardware.bluetooth.a2dp@1.0",
         "android.hardware.bluetooth.audio@2.0",
         "libaudioclient",
@@ -45,8 +62,6 @@
         "libdl",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libprocessgroup",
         "libprotobuf-cpp-lite",
@@ -67,6 +82,7 @@
         "libFraunhoferAAC",
         "libg722codec",
         "libudrv-uipc",
+        "libbluetooth_gd", // Gabeldorsche
     ],
     whole_static_libs: [
         "libbt-bta",
@@ -95,6 +111,9 @@
     cflags: [
         "-DBUILDCFG",
     ],
+    sanitize: {
+        scs: true,
+    },
 }
 
 cc_library_static {
@@ -102,13 +121,10 @@
     defaults: ["fluoride_defaults"],
 
     srcs: [
-        "bte_conf.cc",
-        "bte_init.cc",
-        "bte_init_cpp_logging.cc",
-        "bte_logmsg.cc",
-        "bte_main.cc",
-        "stack_config.cc",
+        ":LibBluetoothSources",
+        "shim/entry_for_test.cc",
     ],
+    host_supported: true,
     include_dirs: [
         "system/bt",
         "system/bt/bta/include",
@@ -123,3 +139,33 @@
         "-DBUILDCFG",
     ],
 }
+
+filegroup {
+    name: "BluetoothLegacyShimTestSources",
+    srcs: [
+        "shim/l2cap_test.cc",
+        "shim/test_stack.cc",
+    ]
+}
+
+cc_test {
+    name: "bluetooth_test_legacy",
+    defaults: ["fluoride_defaults",
+               "fluoride_osi_defaults",
+    ],
+    test_suites: ["device-tests"],
+    host_supported: true,
+    srcs: [
+        ":BluetoothLegacyShimTestSources",
+    ],
+    static_libs: [
+        "libgmock",
+        "libbluetooth-for-tests",
+        "libosi",
+    ],
+    shared_libs: [
+        "libchrome",
+        "liblog",
+    ],
+}
+
diff --git a/main/bte_main.cc b/main/bte_main.cc
index 0498439..1628976 100644
--- a/main/bte_main.cc
+++ b/main/bte_main.cc
@@ -53,6 +53,8 @@
 #include "osi/include/future.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
+#include "shim/hci_layer.h"
+#include "shim/shim.h"
 #include "stack_config.h"
 
 /*******************************************************************************
@@ -155,8 +157,14 @@
 void bte_main_enable() {
   APPL_TRACE_DEBUG("%s", __func__);
 
-  module_start_up(get_module(BTSNOOP_MODULE));
-  module_start_up(get_module(HCI_MODULE));
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    LOG_INFO(LOG_TAG, "%s Gd shim module enabled", __func__);
+    module_start_up(get_module(GD_SHIM_MODULE));
+    module_start_up(get_module(GD_HCI_MODULE));
+  } else {
+    module_start_up(get_module(BTSNOOP_MODULE));
+    module_start_up(get_module(HCI_MODULE));
+  }
 
   BTU_StartUp();
 }
@@ -174,8 +182,14 @@
 void bte_main_disable(void) {
   APPL_TRACE_DEBUG("%s", __func__);
 
-  module_shut_down(get_module(HCI_MODULE));
-  module_shut_down(get_module(BTSNOOP_MODULE));
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    LOG_INFO(LOG_TAG, "%s Gd shim module enabled", __func__);
+    module_shut_down(get_module(GD_HCI_MODULE));
+    module_shut_down(get_module(GD_SHIM_MODULE));
+  } else {
+    module_shut_down(get_module(HCI_MODULE));
+    module_shut_down(get_module(BTSNOOP_MODULE));
+  }
 
   BTU_ShutDown();
 }
diff --git a/main/shim/btm.cc b/main/shim/btm.cc
new file mode 100644
index 0000000..7ebbf90
--- /dev/null
+++ b/main/shim/btm.cc
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_shim_btm"
+
+#include <algorithm>
+#include <cstring>
+
+#include "main/shim/btm.h"
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+
+bluetooth::shim::Btm::Btm() {}
+
+static constexpr size_t kMaxInquiryResultSize = 4096;
+static uint8_t inquiry_result_buf[kMaxInquiryResultSize];
+
+static int inquiry_type_ = 0;
+
+static constexpr uint8_t kInquiryResultMode = 0;
+static constexpr uint8_t kInquiryResultWithRssiMode = 1;
+static constexpr uint8_t kExtendedInquiryResultMode = 2;
+
+static constexpr size_t kRemoteDeviceNameLength = 248;
+
+extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_process_inq_complete(uint8_t status, uint8_t result_type);
+extern void btm_process_inq_results(uint8_t* p, uint8_t result_mode);
+
+using BtmRemoteDeviceName = tBTM_REMOTE_DEV_NAME;
+
+/**
+ *
+ */
+void bluetooth::shim::Btm::OnInquiryResult(std::vector<const uint8_t> result) {
+  CHECK(result.size() < kMaxInquiryResultSize);
+
+  std::copy(result.begin(), result.end(), inquiry_result_buf);
+  btm_process_inq_results(inquiry_result_buf, kInquiryResultMode);
+}
+
+void bluetooth::shim::Btm::OnInquiryResultWithRssi(
+    std::vector<const uint8_t> result) {
+  CHECK(result.size() < kMaxInquiryResultSize);
+
+  std::copy(result.begin(), result.end(), inquiry_result_buf);
+  btm_process_inq_results(inquiry_result_buf, kInquiryResultWithRssiMode);
+}
+
+void bluetooth::shim::Btm::OnExtendedInquiryResult(
+    std::vector<const uint8_t> result) {
+  CHECK(result.size() < kMaxInquiryResultSize);
+
+  std::copy(result.begin(), result.end(), inquiry_result_buf);
+  btm_process_inq_results(inquiry_result_buf, kExtendedInquiryResultMode);
+}
+
+void bluetooth::shim::Btm::OnInquiryComplete(uint16_t status) {
+  btm_process_inq_complete(status, inquiry_type_);
+}
+
+bool bluetooth::shim::Btm::SetInquiryFilter(uint8_t mode, uint8_t type,
+                                            tBTM_INQ_FILT_COND data) {
+  switch (mode) {
+    case kInquiryModeOff:
+      break;
+    case kLimitedInquiryMode:
+      LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+      break;
+    case kGeneralInquiryMode:
+      LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+      break;
+    default:
+      LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+      return false;
+  }
+  return true;
+}
+
+void bluetooth::shim::Btm::SetFilterInquiryOnAddress() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetFilterInquiryOnDevice() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::ClearInquiryFilter() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+bool bluetooth::shim::Btm::SetStandardInquiryResultMode() {
+  bluetooth::shim::GetInquiry()->SetStandardInquiryResultMode();
+  return true;
+}
+
+bool bluetooth::shim::Btm::SetInquiryWithRssiResultMode() {
+  bluetooth::shim::GetInquiry()->SetInquiryWithRssiResultMode();
+  return true;
+}
+
+bool bluetooth::shim::Btm::SetExtendedInquiryResultMode() {
+  bluetooth::shim::GetInquiry()->SetExtendedInquiryResultMode();
+  return true;
+}
+
+void bluetooth::shim::Btm::SetInterlacedInquiryScan() {
+  bluetooth::shim::GetInquiry()->SetInterlacedScan();
+}
+
+void bluetooth::shim::Btm::SetStandardInquiryScan() {
+  bluetooth::shim::GetInquiry()->SetStandardScan();
+}
+
+bool bluetooth::shim::Btm::IsInterlacedScanSupported() const {
+  // TODO(cmanton) This is a controller query
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return true;
+}
+
+/**
+ * One shot inquiry
+ */
+bool bluetooth::shim::Btm::StartInquiry(uint8_t mode, uint8_t duration,
+                                        uint8_t max_responses) {
+  switch (mode) {
+    case kInquiryModeOff:
+      LOG_DEBUG(LOG_TAG, "%s Stopping inquiry mode", __func__);
+      bluetooth::shim::GetInquiry()->StopInquiry();
+      bluetooth::shim::GetInquiry()->UnregisterInquiryResult();
+      bluetooth::shim::GetInquiry()->UnregisterInquiryResultWithRssi();
+      bluetooth::shim::GetInquiry()->UnregisterExtendedInquiryResult();
+      bluetooth::shim::GetInquiry()->UnregisterInquiryComplete();
+      break;
+
+    case kLimitedInquiryMode:
+    case kGeneralInquiryMode:
+      bluetooth::shim::GetInquiry()->RegisterInquiryResult(
+          std::bind(&Btm::OnInquiryResult, this, std::placeholders::_1));
+      bluetooth::shim::GetInquiry()->RegisterInquiryResultWithRssi(std::bind(
+          &Btm::OnInquiryResultWithRssi, this, std::placeholders::_1));
+      bluetooth::shim::GetInquiry()->RegisterExtendedInquiryResult(std::bind(
+          &Btm::OnExtendedInquiryResult, this, std::placeholders::_1));
+      bluetooth::shim::GetInquiry()->RegisterInquiryComplete(
+          std::bind(&Btm::OnInquiryComplete, this, std::placeholders::_1));
+
+      if (mode == kLimitedInquiryMode) {
+        LOG_DEBUG(
+            LOG_TAG,
+            "%s Starting limited inquiry mode duration:%hhd max responses:%hhd",
+            __func__, duration, max_responses);
+        bluetooth::shim::GetInquiry()->StartLimitedInquiry(duration,
+                                                           max_responses);
+      } else {
+        LOG_DEBUG(
+            LOG_TAG,
+            "%s Starting general inquiry mode duration:%hhd max responses:%hhd",
+            __func__, duration, max_responses);
+        bluetooth::shim::GetInquiry()->StartGeneralInquiry(duration,
+                                                           max_responses);
+      }
+      break;
+
+    default:
+      LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+      return false;
+  }
+  return true;
+}
+
+void bluetooth::shim::Btm::CancelInquiry() {
+  bluetooth::shim::GetInquiry()->StopInquiry();
+}
+
+bool bluetooth::shim::Btm::IsInquiryActive() const {
+  return IsGeneralInquiryActive() || IsLimitedInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsGeneralInquiryActive() const {
+  return bluetooth::shim::GetInquiry()->IsGeneralInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsLimitedInquiryActive() const {
+  return bluetooth::shim::GetInquiry()->IsLimitedInquiryActive();
+}
+
+/**
+ * Periodic
+ */
+bool bluetooth::shim::Btm::StartPeriodicInquiry(
+    uint8_t mode, uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+    uint16_t min_delay, tBTM_INQ_RESULTS_CB* p_results_cb) {
+  switch (mode) {
+    case kInquiryModeOff:
+      bluetooth::shim::GetInquiry()->StopPeriodicInquiry();
+      break;
+
+    case kLimitedInquiryMode:
+    case kGeneralInquiryMode:
+      if (mode == kLimitedInquiryMode) {
+        LOG_DEBUG(LOG_TAG, "%s Starting limited periodic inquiry mode",
+                  __func__);
+        bluetooth::shim::GetInquiry()->StartLimitedPeriodicInquiry(
+            duration, max_responses, max_delay, min_delay);
+      } else {
+        LOG_DEBUG(LOG_TAG, "%s Starting general periodic inquiry mode",
+                  __func__);
+        bluetooth::shim::GetInquiry()->StartGeneralPeriodicInquiry(
+            duration, max_responses, max_delay, min_delay);
+      }
+      break;
+
+    default:
+      LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+      return false;
+  }
+  return true;
+}
+
+void bluetooth::shim::Btm::CancelPeriodicInquiry() {
+  bluetooth::shim::GetInquiry()->StopPeriodicInquiry();
+}
+
+bool bluetooth::shim::Btm::IsGeneralPeriodicInquiryActive() const {
+  return bluetooth::shim::GetInquiry()->IsGeneralPeriodicInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsLimitedPeriodicInquiryActive() const {
+  return bluetooth::shim::GetInquiry()->IsLimitedPeriodicInquiryActive();
+}
+
+/**
+ * Discoverability
+ */
+void bluetooth::shim::Btm::SetClassicGeneralDiscoverability(uint16_t window,
+                                                            uint16_t interval) {
+  bluetooth::shim::GetInquiry()->SetScanActivity(interval, window);
+  bluetooth::shim::GetDiscoverability()->StartGeneralDiscoverability();
+}
+
+void bluetooth::shim::Btm::SetClassicLimitedDiscoverability(uint16_t window,
+                                                            uint16_t interval) {
+  bluetooth::shim::GetInquiry()->SetScanActivity(interval, window);
+  bluetooth::shim::GetDiscoverability()->StartLimitedDiscoverability();
+}
+
+void bluetooth::shim::Btm::SetClassicDiscoverabilityOff() {
+  bluetooth::shim::GetDiscoverability()->StopDiscoverability();
+}
+
+DiscoverabilityState bluetooth::shim::Btm::GetClassicDiscoverabilityState()
+    const {
+  DiscoverabilityState state{.mode = BTM_NON_DISCOVERABLE};
+  bluetooth::shim::GetInquiry()->GetScanActivity(state.interval, state.window);
+
+  if (bluetooth::shim::GetDiscoverability()
+          ->IsGeneralDiscoverabilityEnabled()) {
+    state.mode = BTM_GENERAL_DISCOVERABLE;
+  } else if (bluetooth::shim::GetDiscoverability()
+                 ->IsLimitedDiscoverabilityEnabled()) {
+    state.mode = BTM_LIMITED_DISCOVERABLE;
+  }
+  return state;
+}
+
+void bluetooth::shim::Btm::SetLeGeneralDiscoverability() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeLimitedDiscoverability() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeDiscoverabilityOff() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+DiscoverabilityState bluetooth::shim::Btm::GetLeDiscoverabilityState() const {
+  DiscoverabilityState state{
+      .mode = kDiscoverableModeOff,
+      .interval = 0,
+      .window = 0,
+  };
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return state;
+}
+
+/**
+ * Connectability
+ */
+void bluetooth::shim::Btm::SetClassicConnectibleOn() {
+  bluetooth::shim::GetConnectability()->StartConnectability();
+}
+
+void bluetooth::shim::Btm::SetClassicConnectibleOff() {
+  bluetooth::shim::GetConnectability()->StopConnectability();
+}
+
+ConnectabilityState bluetooth::shim::Btm::GetClassicConnectabilityState()
+    const {
+  ConnectabilityState state;
+  bluetooth::shim::GetPage()->GetScanActivity(state.interval, state.window);
+
+  if (bluetooth::shim::GetConnectability()->IsConnectable()) {
+    state.mode = BTM_CONNECTABLE;
+  } else {
+    state.mode = BTM_NON_CONNECTABLE;
+  }
+  return state;
+}
+
+void bluetooth::shim::Btm::SetInterlacedPageScan() {
+  bluetooth::shim::GetPage()->SetInterlacedScan();
+}
+
+void bluetooth::shim::Btm::SetStandardPageScan() {
+  bluetooth::shim::GetPage()->SetStandardScan();
+}
+
+void bluetooth::shim::Btm::SetLeConnectibleOn() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeConnectibleOff() {
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+ConnectabilityState bluetooth::shim::Btm::GetLeConnectabilityState() const {
+  ConnectabilityState state{
+      .mode = kConnectibleModeOff,
+      .interval = 0,
+      .window = 0,
+  };
+  LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return state;
+}
+
+bool bluetooth::shim::Btm::IsLeAclConnected(
+    const RawAddress& raw_address) const {
+  // TODO(cmanton) Check current acl's for this address and indicate if there is
+  // an LE option.  For now ignore and default to classic.
+  LOG_INFO(LOG_TAG, "%s Le acl connection check is temporarily unsupported",
+           __func__);
+  return false;
+}
+
+bluetooth::shim::BtmStatus bluetooth::shim::Btm::ReadClassicRemoteDeviceName(
+    const RawAddress& raw_address, tBTM_CMPL_CB* callback) {
+  if (!CheckClassicAclLink(raw_address)) {
+    return bluetooth::shim::BTM_UNKNOWN_ADDR;
+  }
+
+  if (!classic_read_remote_name_.Start(raw_address)) {
+    LOG_INFO(LOG_TAG, "%s Read remote name is currently busy address:%s",
+             __func__, raw_address.ToString().c_str());
+    return bluetooth::shim::BTM_BUSY;
+  }
+
+  LOG_DEBUG(LOG_TAG, "%s Start read name from address:%s", __func__,
+            raw_address.ToString().c_str());
+  bluetooth::shim::GetName()->ReadRemoteNameRequest(
+      classic_read_remote_name_.AddressString(),
+      [this, callback](
+          std::string address_string, uint8_t hci_status,
+          std::array<uint8_t, kRemoteDeviceNameLength> remote_name) {
+        RawAddress raw_address;
+        RawAddress::FromString(address_string, raw_address);
+
+        BtmRemoteDeviceName name{
+            .status = (hci_status == 0) ? (BTM_SUCCESS) : (BTM_BAD_VALUE_RET),
+            .bd_addr = raw_address,
+            .length = kRemoteDeviceNameLength,
+        };
+        std::copy(remote_name.begin(), remote_name.end(), name.remote_bd_name);
+        LOG_DEBUG(LOG_TAG, "%s Finish read name from address:%s name:%s",
+                  __func__, address_string.c_str(), name.remote_bd_name);
+        callback(&name);
+        classic_read_remote_name_.Stop();
+      });
+  return bluetooth::shim::BTM_CMD_STARTED;
+}
+
+bluetooth::shim::BtmStatus bluetooth::shim::Btm::ReadLeRemoteDeviceName(
+    const RawAddress& raw_address, tBTM_CMPL_CB* callback) {
+  if (!CheckLeAclLink(raw_address)) {
+    return bluetooth::shim::BTM_UNKNOWN_ADDR;
+  }
+
+  if (!le_read_remote_name_.Start(raw_address)) {
+    return bluetooth::shim::BTM_BUSY;
+  }
+
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s need access to GATT module", __func__);
+  return bluetooth::shim::BTM_UNKNOWN_ADDR;
+}
+
+bluetooth::shim::BtmStatus
+bluetooth::shim::Btm::CancelAllReadRemoteDeviceName() {
+  if (classic_read_remote_name_.IsInProgress() ||
+      le_read_remote_name_.IsInProgress()) {
+    if (classic_read_remote_name_.IsInProgress()) {
+      bluetooth::shim::GetName()->CancelRemoteNameRequest(
+          classic_read_remote_name_.AddressString(),
+          [this](std::string address_string, uint8_t status) {
+            classic_read_remote_name_.Stop();
+          });
+    }
+    if (le_read_remote_name_.IsInProgress()) {
+      LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s need access to GATT module",
+               __func__);
+    }
+    return bluetooth::shim::BTM_UNKNOWN_ADDR;
+  }
+  LOG_INFO(LOG_TAG,
+           "%s Cancelling classic remote device name without one in progress",
+           __func__);
+  return bluetooth::shim::BTM_WRONG_MODE;
+}
diff --git a/main/shim/btm.h b/main/shim/btm.h
new file mode 100644
index 0000000..6f9c00b
--- /dev/null
+++ b/main/shim/btm.h
@@ -0,0 +1,198 @@
+/*
+ * 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 <cstdint>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include "stack/include/btm_api_types.h"
+
+/* Discoverable modes */
+static constexpr int kDiscoverableModeOff = 0;
+static constexpr int kLimitedDiscoverableMode = 1;
+static constexpr int kGeneralDiscoverableMode = 2;
+
+/* Inquiry modes */
+// NOTE: The inquiry general/limited are reversed from the discoverability
+// constants
+static constexpr int kInquiryModeOff = 0;
+static constexpr int kGeneralInquiryMode = 1;
+static constexpr int kLimitedInquiryMode = 2;
+
+/* Connectable modes */
+static constexpr int kConnectibleModeOff = 0;
+static constexpr int kConnectibleModeOn = 1;
+
+/* Inquiry and page scan modes */
+static constexpr int kStandardScanType = 0;
+static constexpr int kInterlacedScanType = 1;
+
+/* Inquiry result modes */
+static constexpr int kStandardInquiryResult = 0;
+static constexpr int kInquiryResultWithRssi = 1;
+static constexpr int kExtendedInquiryResult = 2;
+
+/* Inquiry filter types */
+static constexpr int kClearInquiryFilter = 0;
+static constexpr int kFilterOnDeviceClass = 1;
+static constexpr int kFilterOnAddress = 2;
+
+using DiscoverabilityState = struct {
+  int mode;
+  uint16_t interval;
+  uint16_t window;
+};
+using ConnectabilityState = DiscoverabilityState;
+
+namespace bluetooth {
+namespace shim {
+
+using BtmStatus = enum : uint16_t {
+  BTM_SUCCESS = 0,         /* 0  Command succeeded                 */
+  BTM_CMD_STARTED,         /* 1  Command started OK.               */
+  BTM_BUSY,                /* 2  Device busy with another command  */
+  BTM_NO_RESOURCES,        /* 3  No resources to issue command     */
+  BTM_MODE_UNSUPPORTED,    /* 4  Request for 1 or more unsupported modes */
+  BTM_ILLEGAL_VALUE,       /* 5  Illegal parameter value           */
+  BTM_WRONG_MODE,          /* 6  Device in wrong mode for request  */
+  BTM_UNKNOWN_ADDR,        /* 7  Unknown remote BD address         */
+  BTM_DEVICE_TIMEOUT,      /* 8  Device timeout                    */
+  BTM_BAD_VALUE_RET,       /* 9  A bad value was received from HCI */
+  BTM_ERR_PROCESSING,      /* 10 Generic error                     */
+  BTM_NOT_AUTHORIZED,      /* 11 Authorization failed              */
+  BTM_DEV_RESET,           /* 12 Device has been reset             */
+  BTM_CMD_STORED,          /* 13 request is stored in control block */
+  BTM_ILLEGAL_ACTION,      /* 14 state machine gets illegal command */
+  BTM_DELAY_CHECK,         /* 15 delay the check on encryption */
+  BTM_SCO_BAD_LENGTH,      /* 16 Bad SCO over HCI data length */
+  BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set  */
+  BTM_FAILED_ON_SECURITY,  /* 18 security failed                   */
+  BTM_REPEATED_ATTEMPTS,   /* 19 repeated attempts for LE security requests */
+  BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be
+                                     supported */
+  BTM_DEV_BLACKLISTED             /* 21 The device is Blacklisted */
+};
+
+class ReadRemoteName {
+ public:
+  bool Start(RawAddress raw_address) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    if (in_progress_) {
+      return false;
+    }
+    raw_address_ = raw_address;
+    in_progress_ = true;
+    return true;
+  }
+
+  void Stop() {
+    std::unique_lock<std::mutex> lock(mutex_);
+    raw_address_ = RawAddress::kEmpty;
+    in_progress_ = false;
+  }
+
+  bool IsInProgress() const { return in_progress_; }
+
+  std::string AddressString() const { return raw_address_.ToString(); }
+
+  ReadRemoteName() : in_progress_{false}, raw_address_(RawAddress::kEmpty) {}
+
+ private:
+  bool in_progress_;
+  RawAddress raw_address_;
+  std::mutex mutex_;
+};
+
+class Btm {
+ public:
+  Btm();
+
+  // Callbacks
+  void OnInquiryResult(std::vector<const uint8_t> result);
+  void OnInquiryResultWithRssi(std::vector<const uint8_t> result);
+  void OnExtendedInquiryResult(std::vector<const uint8_t> result);
+  void OnInquiryComplete(uint16_t status);
+
+  // Inquiry API
+  bool SetInquiryFilter(uint8_t mode, uint8_t type, tBTM_INQ_FILT_COND data);
+  void SetFilterInquiryOnAddress();
+  void SetFilterInquiryOnDevice();
+  void ClearInquiryFilter();
+
+  bool SetStandardInquiryResultMode();
+  bool SetInquiryWithRssiResultMode();
+  bool SetExtendedInquiryResultMode();
+
+  void SetInterlacedInquiryScan();
+  void SetStandardInquiryScan();
+  bool IsInterlacedScanSupported() const;
+
+  bool StartInquiry(uint8_t mode, uint8_t duration, uint8_t max_responses);
+  void CancelInquiry();
+  bool IsInquiryActive() const;
+  bool IsGeneralInquiryActive() const;
+  bool IsLimitedInquiryActive() const;
+
+  bool StartPeriodicInquiry(uint8_t mode, uint8_t duration,
+                            uint8_t max_responses, uint16_t max_delay,
+                            uint16_t min_delay,
+                            tBTM_INQ_RESULTS_CB* p_results_cb);
+  void CancelPeriodicInquiry();
+  bool IsGeneralPeriodicInquiryActive() const;
+  bool IsLimitedPeriodicInquiryActive() const;
+
+  void SetClassicGeneralDiscoverability(uint16_t window, uint16_t interval);
+  void SetClassicLimitedDiscoverability(uint16_t window, uint16_t interval);
+  void SetClassicDiscoverabilityOff();
+  DiscoverabilityState GetClassicDiscoverabilityState() const;
+
+  void SetLeGeneralDiscoverability();
+  void SetLeLimitedDiscoverability();
+  void SetLeDiscoverabilityOff();
+  DiscoverabilityState GetLeDiscoverabilityState() const;
+
+  void SetClassicConnectibleOn();
+  void SetClassicConnectibleOff();
+  ConnectabilityState GetClassicConnectabilityState() const;
+  void SetInterlacedPageScan();
+  void SetStandardPageScan();
+
+  void SetLeConnectibleOn();
+  void SetLeConnectibleOff();
+  ConnectabilityState GetLeConnectabilityState() const;
+
+  bool IsLeAclConnected(const RawAddress& raw_address) const;
+
+  // Remote device name
+  BtmStatus ReadClassicRemoteDeviceName(const RawAddress& raw_address,
+                                        tBTM_CMPL_CB* callback);
+  BtmStatus ReadLeRemoteDeviceName(const RawAddress& raw_address,
+                                   tBTM_CMPL_CB* callback);
+  BtmStatus CancelAllReadRemoteDeviceName();
+
+ private:
+  ReadRemoteName le_read_remote_name_;
+  ReadRemoteName classic_read_remote_name_;
+  // TODO(cmanton) abort if there is no classic acl link up
+  bool CheckClassicAclLink(const RawAddress& raw_address) { return true; }
+  bool CheckLeAclLink(const RawAddress& raw_address) { return true; }
+};
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/btm_api.cc b/main/shim/btm_api.cc
new file mode 100644
index 0000000..a8adee8
--- /dev/null
+++ b/main/shim/btm_api.cc
@@ -0,0 +1,1411 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_shim_btm"
+
+#include <base/callback.h>
+
+#include "main/shim/btm.h"
+#include "main/shim/btm_api.h"
+#include "osi/include/log.h"
+#include "stack/btm/btm_int_types.h"
+
+static bluetooth::shim::Btm shim_btm;
+
+/*******************************************************************************
+ *
+ * Function         BTM_StartInquiry
+ *
+ * Description      This function is called to start an inquiry.
+ *
+ * Parameters:      p_inqparms - pointer to the inquiry information
+ *                      mode - GENERAL or LIMITED inquiry, BR/LE bit mask
+ *                             seperately
+ *                      duration - length in 1.28 sec intervals (If '0', the
+ *                                 inquiry is CANCELLED)
+ *                      max_resps - maximum amount of devices to search for
+ *                                  before ending the inquiry
+ *                      filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ *                                         BTM_FILTER_COND_DEVICE_CLASS, or
+ *                                         BTM_FILTER_COND_BD_ADDR
+ *                      filter_cond - value for the filter (based on
+ *                                                          filter_cond_type)
+ *
+ *                  p_results_cb   - Pointer to the callback routine which gets
+ *                                called upon receipt of an inquiry result. If
+ *                                this field is NULL, the application is not
+ *                                notified.
+ *
+ *                  p_cmpl_cb   - Pointer to the callback routine which gets
+ *                                called upon completion.  If this field is
+ *                                NULL, the application is not notified when
+ *                                completed.
+ * Returns          tBTM_STATUS
+ *                  BTM_CMD_STARTED if successfully initiated
+ *                  BTM_BUSY if already in progress
+ *                  BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ *                  BTM_NO_RESOURCES if could not allocate resources to start
+ *                                   the command
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+                                              tBTM_INQ_RESULTS_CB* p_results_cb,
+                                              tBTM_CMPL_CB* p_cmpl_cb) {
+  CHECK(p_inqparms != nullptr);
+  CHECK(p_results_cb != nullptr);
+  CHECK(p_cmpl_cb != nullptr);
+
+  uint8_t classic_mode = p_inqparms->mode & 0x0f;
+  // TODO(cmanton) Setup the LE portion too
+  uint8_t le_mode = p_inqparms->mode >> 4;
+
+  LOG_INFO(LOG_TAG, "%s Start inquiry mode classic:%hhd le:%hhd", __func__,
+           classic_mode, le_mode);
+
+  if (!shim_btm.SetInquiryFilter(classic_mode, p_inqparms->filter_cond_type,
+                                 p_inqparms->filter_cond)) {
+    LOG_WARN(LOG_TAG, "%s Unable to set inquiry filter", __func__);
+    return BTM_ERR_PROCESSING;
+  }
+
+  if (!shim_btm.StartInquiry(classic_mode, p_inqparms->duration,
+                             p_inqparms->max_resps)) {
+    LOG_WARN(LOG_TAG, "%s Unable to start inquiry", __func__);
+    return BTM_ERR_PROCESSING;
+  }
+  return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPeriodicInquiryMode
+ *
+ * Description      This function is called to set the device periodic inquiry
+ *                  mode. If the duration is zero, the periodic inquiry mode is
+ *                  cancelled.
+ *
+ *                  Note: We currently do not allow concurrent inquiry and
+ *                  periodic inquiry.
+ *
+ * Parameters:      p_inqparms - pointer to the inquiry information
+ *                      mode - GENERAL or LIMITED inquiry
+ *                      duration - length in 1.28 sec intervals (If '0', the
+ *                                 inquiry is CANCELLED)
+ *                      max_resps - maximum amount of devices to search for
+ *                                  before ending the inquiry
+ *                      filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ *                                         BTM_FILTER_COND_DEVICE_CLASS, or
+ *                                         BTM_FILTER_COND_BD_ADDR
+ *                      filter_cond - value for the filter (based on
+ *                                                          filter_cond_type)
+ *
+ *                  max_delay - maximum amount of time between successive
+ *                              inquiries
+ *                  min_delay - minimum amount of time between successive
+ *                              inquiries
+ *                  p_results_cb - callback returning pointer to results
+ *                              (tBTM_INQ_RESULTS)
+ *
+ * Returns          BTM_CMD_STARTED if successfully started
+ *                  BTM_ILLEGAL_VALUE if a bad parameter is detected
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_SUCCESS - if cancelling the periodic inquiry
+ *                  BTM_BUSY - if an inquiry is already active
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetPeriodicInquiryMode(
+    tBTM_INQ_PARMS* p_inqparms, uint16_t max_delay, uint16_t min_delay,
+    tBTM_INQ_RESULTS_CB* p_results_cb) {
+  CHECK(p_inqparms != nullptr);
+  CHECK(p_results_cb != nullptr);
+
+  if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN ||
+      p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH ||
+      min_delay <= p_inqparms->duration ||
+      min_delay < BTM_PER_INQ_MIN_MIN_PERIOD ||
+      min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || max_delay <= min_delay ||
+      max_delay < BTM_PER_INQ_MIN_MAX_PERIOD) {
+    return (BTM_ILLEGAL_VALUE);
+  }
+
+  if (shim_btm.IsInquiryActive()) {
+    return BTM_BUSY;
+  }
+
+  switch (p_inqparms->filter_cond_type) {
+    case kClearInquiryFilter:
+      shim_btm.ClearInquiryFilter();
+      return BTM_SUCCESS;
+      break;
+    case kFilterOnDeviceClass:
+      shim_btm.SetFilterInquiryOnDevice();
+      return BTM_SUCCESS;
+      break;
+    case kFilterOnAddress:
+      shim_btm.SetFilterInquiryOnAddress();
+      return BTM_SUCCESS;
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+  }
+  return BTM_MODE_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDiscoverability
+ *
+ * Description      This function is called to set the device into or out of
+ *                  discoverable mode. Discoverable mode means inquiry
+ *                  scans are enabled.  If a value of '0' is entered for window
+ *                  or interval, the default values are used.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_BUSY if a setting of the filter is already in progress
+ *                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ *                  BTM_ILLEGAL_VALUE if a bad parameter was detected
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetDiscoverability(uint16_t discoverable_mode,
+                                                    uint16_t window,
+                                                    uint16_t interval) {
+  uint16_t classic_discoverable_mode = discoverable_mode & 0xff;
+  uint16_t le_discoverable_mode = discoverable_mode >> 8;
+
+  if (window == 0) window = BTM_DEFAULT_DISC_WINDOW;
+  if (interval == 0) interval = BTM_DEFAULT_DISC_INTERVAL;
+
+  switch (le_discoverable_mode) {
+    case kDiscoverableModeOff:
+      shim_btm.SetLeDiscoverabilityOff();
+      break;
+    case kLimitedDiscoverableMode:
+      shim_btm.SetLeLimitedDiscoverability();
+      break;
+    case kGeneralDiscoverableMode:
+      shim_btm.SetLeGeneralDiscoverability();
+      break;
+  }
+
+  switch (classic_discoverable_mode) {
+    case kDiscoverableModeOff:
+      shim_btm.SetClassicDiscoverabilityOff();
+      break;
+    case kLimitedDiscoverableMode:
+      shim_btm.SetClassicLimitedDiscoverability(window, interval);
+      break;
+    case kGeneralDiscoverableMode:
+      shim_btm.SetClassicGeneralDiscoverability(window, interval);
+      break;
+  }
+
+  return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetInquiryScanType
+ *
+ * Description      This function is called to set the iquiry scan-type to
+ *                  standard or interlaced.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_MODE_UNSUPPORTED if not a 1.2 device
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetInquiryScanType(uint16_t scan_type) {
+  switch (scan_type) {
+    case kInterlacedScanType:
+      shim_btm.SetInterlacedInquiryScan();
+      return BTM_SUCCESS;
+      break;
+    case kStandardScanType:
+      shim_btm.SetStandardInquiryScan();
+      return BTM_SUCCESS;
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+  }
+  return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPageScanType
+ *
+ * Description      This function is called to set the page scan-type to
+ *                  standard or interlaced.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_MODE_UNSUPPORTED if not a 1.2 device
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetPageScanType(uint16_t scan_type) {
+  switch (scan_type) {
+    case kInterlacedScanType:
+      if (!shim_btm.IsInterlacedScanSupported()) {
+        return BTM_MODE_UNSUPPORTED;
+      }
+      shim_btm.SetInterlacedPageScan();
+      return BTM_SUCCESS;
+      break;
+    case kStandardScanType:
+      shim_btm.SetStandardPageScan();
+      return BTM_SUCCESS;
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+  }
+  return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetInquiryMode
+ *
+ * Description      This function is called to set standard or with RSSI
+ *                  mode of the inquiry for local device.
+ *
+ * Output Params:   mode - standard, with RSSI, extended
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ *                  BTM_ILLEGAL_VALUE if a bad parameter was detected
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetInquiryMode(uint8_t inquiry_mode) {
+  switch (inquiry_mode) {
+    case kStandardInquiryResult:
+      if (shim_btm.SetStandardInquiryResultMode()) {
+        return BTM_SUCCESS;
+      }
+      break;
+    case kInquiryResultWithRssi:
+      if (shim_btm.SetInquiryWithRssiResultMode()) {
+        return BTM_SUCCESS;
+      }
+      break;
+    case kExtendedInquiryResult:
+      if (shim_btm.SetExtendedInquiryResultMode()) {
+        return BTM_SUCCESS;
+      }
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+  }
+  return BTM_MODE_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDiscoverability
+ *
+ * Description      This function is called to read the current discoverability
+ *                  mode of the device.
+ *
+ * Output Params:   p_window - current inquiry scan duration
+ *                  p_interval - current inquiry scan interval
+ *
+ * Returns          BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ *                  BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_ReadDiscoverability(uint16_t* p_window,
+                                                  uint16_t* p_interval) {
+  DiscoverabilityState state = shim_btm.GetClassicDiscoverabilityState();
+
+  if (p_interval) *p_interval = state.interval;
+  if (p_window) *p_window = state.window;
+
+  return state.mode;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelPeriodicInquiry
+ *
+ * Description      This function cancels a periodic inquiry
+ *
+ * Returns
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_SUCCESS - if cancelling the periodic inquiry
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelPeriodicInquiry(void) {
+  shim_btm.CancelPeriodicInquiry();
+  return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetConnectability
+ *
+ * Description      This function is called to set the device into or out of
+ *                  connectable mode. Discoverable mode means page scans are
+ *                  enabled.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_ILLEGAL_VALUE if a bad parameter is detected
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetConnectability(uint16_t page_mode,
+                                                   uint16_t window,
+                                                   uint16_t interval) {
+  uint16_t classic_connectible_mode = page_mode & 0xff;
+  uint16_t le_connectible_mode = page_mode >> 8;
+
+  if (!window) window = BTM_DEFAULT_CONN_WINDOW;
+  if (!interval) interval = BTM_DEFAULT_CONN_INTERVAL;
+
+  switch (le_connectible_mode) {
+    case kConnectibleModeOff:
+      shim_btm.SetLeConnectibleOff();
+      break;
+    case kConnectibleModeOn:
+      shim_btm.SetLeConnectibleOn();
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+      break;
+  }
+
+  switch (classic_connectible_mode) {
+    case kConnectibleModeOff:
+      shim_btm.SetClassicConnectibleOff();
+      break;
+    case kConnectibleModeOn:
+      shim_btm.SetClassicConnectibleOn();
+      break;
+    default:
+      return BTM_ILLEGAL_VALUE;
+      break;
+  }
+  return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectability
+ *
+ * Description      This function is called to read the current discoverability
+ *                  mode of the device.
+ * Output Params    p_window - current page scan duration
+ *                  p_interval - current time between page scans
+ *
+ * Returns          BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_ReadConnectability(uint16_t* p_window,
+                                                 uint16_t* p_interval) {
+  ConnectabilityState state = shim_btm.GetClassicConnectabilityState();
+
+  if (p_window) *p_window = state.window;
+  if (p_interval) *p_interval = state.interval;
+
+  return state.mode;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsInquiryActive
+ *
+ * Description      This function returns a bit mask of the current inquiry
+ *                  state
+ *
+ * Returns          BTM_INQUIRY_INACTIVE if inactive (0)
+ *                  BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ *                  BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ *                  BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_IsInquiryActive(void) {
+  if (shim_btm.IsLimitedInquiryActive()) {
+    return BTM_LIMITED_INQUIRY_ACTIVE;
+  } else if (shim_btm.IsGeneralInquiryActive()) {
+    return BTM_GENERAL_INQUIRY_ACTIVE;
+  } else if (shim_btm.IsGeneralPeriodicInquiryActive() ||
+             shim_btm.IsLimitedPeriodicInquiryActive()) {
+    return BTM_PERIODIC_INQUIRY_ACTIVE;
+  }
+  return BTM_INQUIRY_INACTIVE;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelInquiry
+ *
+ * Description      This function cancels an inquiry if active
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelInquiry(void) {
+  shim_btm.CancelInquiry();
+  return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteDeviceName
+ *
+ * Description      This function initiates a remote device HCI command to the
+ *                  controller and calls the callback when the process has
+ *                  completed.
+ *
+ * Input Params:    remote_bda      - device address of name to retrieve
+ *                  p_cb            - callback function called when
+ *                                    BTM_CMD_STARTED is returned.
+ *                                    A pointer to tBTM_REMOTE_DEV_NAME is
+ *                                    passed to the callback.
+ *
+ * Returns
+ *                  BTM_CMD_STARTED is returned if the request was successfully
+ *                                  sent to HCI.
+ *                  BTM_BUSY if already in progress
+ *                  BTM_UNKNOWN_ADDR if device address is bad
+ *                  BTM_NO_RESOURCES if could not allocate resources to start
+ *                                   the command
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ReadRemoteDeviceName(
+    const RawAddress& raw_address, tBTM_CMPL_CB* callback,
+    tBT_TRANSPORT transport) {
+  CHECK(callback != nullptr);
+  tBTM_STATUS status = BTM_NO_RESOURCES;
+
+  switch (transport) {
+    case BT_TRANSPORT_LE:
+      status = shim_btm.ReadLeRemoteDeviceName(raw_address, callback);
+      break;
+    case BT_TRANSPORT_BR_EDR:
+      status = shim_btm.ReadClassicRemoteDeviceName(raw_address, callback);
+      break;
+    default:
+      LOG_WARN(LOG_TAG, "%s Unspecified transport:%d", __func__, transport);
+      break;
+  }
+  return status;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelRemoteDeviceName
+ *
+ * Description      This function initiates the cancel request for the specified
+ *                  remote device.
+ *
+ * Input Params:    None
+ *
+ * Returns
+ *                  BTM_CMD_STARTED is returned if the request was successfully
+ *                                  sent to HCI.
+ *                  BTM_NO_RESOURCES if could not allocate resources to start
+ *                                   the command
+ *                  BTM_WRONG_MODE if there is not an active remote name
+ *                                 request.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelRemoteDeviceName(void) {
+  return shim_btm.CancelAllReadRemoteDeviceName();
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbRead
+ *
+ * Description      This function looks through the inquiry database for a match
+ *                  based on Bluetooth Device Address. This is the application's
+ *                  interface to get the inquiry details of a specific BD
+ *                  address.
+ *
+ * Returns          pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbRead(const RawAddress& p_bda) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbFirst
+ *
+ * Description      This function looks through the inquiry database for the
+ *                  first used entry, and returns that. This is used in
+ *                  conjunction with
+ *                  BTM_InqDbNext by applications as a way to walk through the
+ *                  inquiry database.
+ *
+ * Returns          pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbFirst(void) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbNext
+ *
+ * Description      This function looks through the inquiry database for the
+ *                  next used entry, and returns that.  If the input parameter
+ *                  is NULL, the first entry is returned.
+ *
+ * Returns          pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbNext(tBTM_INQ_INFO* p_cur) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_cur != nullptr);
+  return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ClearInqDb
+ *
+ * Description      This function is called to clear out a device or all devices
+ *                  from the inquiry database.
+ *
+ * Parameter        p_bda - (input) BD_ADDR ->  Address of device to clear
+ *                                              (NULL clears all entries)
+ *
+ * Returns          BTM_BUSY if an inquiry, get remote name, or event filter
+ *                          is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ClearInqDb(const RawAddress* p_bda) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  if (p_bda == nullptr) {
+    // clear all entries
+  } else {
+    // clear specific entry
+  }
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadInquiryRspTxPower
+ *
+ * Description      This command will read the inquiry Transmit Power level used
+ *                  to transmit the FHS and EIR data packets. This can be used
+ *                  directly in the Tx Power Level EIR data type.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_cb != nullptr);
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_WriteEIR
+ *
+ * Description      This function is called to write EIR data to controller.
+ *
+ * Parameters       p_buff - allocated HCI command buffer including extended
+ *                           inquriry response
+ *
+ * Returns          BTM_SUCCESS  - if successful
+ *                  BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_WriteEIR(BT_HDR* p_buff) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_buff != nullptr);
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_HasEirService
+ *
+ * Description      This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters       p_eir_uuid - bit map of UUID list
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          true - if found
+ *                  false - if not found
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_HasEirService(const uint32_t* p_eir_uuid,
+                                        uint16_t uuid16) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_eir_uuid != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_HasInquiryEirService
+ *
+ * Description      This function is called to know if UUID in bit map of UUID
+ *                  list.
+ *
+ * Parameters       p_results - inquiry results
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          BTM_EIR_FOUND - if found
+ *                  BTM_EIR_NOT_FOUND - if not found and it is complete list
+ *                  BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+tBTM_EIR_SEARCH_RESULT bluetooth::shim::BTM_HasInquiryEirService(
+    tBTM_INQ_RESULTS* p_results, uint16_t uuid16) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_results != nullptr);
+  return BTM_EIR_UNKNOWN;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_AddEirService
+ *
+ * Description      This function is called to add a service in bit map of UUID
+ *                  list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_eir_uuid != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_RemoveEirService
+ *
+ * Description      This function is called to remove a service in bit map of
+ *                  UUID list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_RemoveEirService(uint32_t* p_eir_uuid,
+                                           uint16_t uuid16) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_eir_uuid != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetEirSupportedServices
+ *
+ * Description      This function is called to get UUID list from bit map of
+ *                  UUID list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  p - reference of current pointer of EIR
+ *                  max_num_uuid16 - max number of UUID can be written in EIR
+ *                  num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns          BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ *                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_GetEirSupportedServices(uint32_t* p_eir_uuid,
+                                                     uint8_t** p,
+                                                     uint8_t max_num_uuid16,
+                                                     uint8_t* p_num_uuid16) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_eir_uuid != nullptr);
+  CHECK(p != nullptr);
+  CHECK(*p != nullptr);
+  CHECK(p_num_uuid16 != nullptr);
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetEirUuidList
+ *
+ * Description      This function parses EIR and returns UUID list.
+ *
+ * Parameters       p_eir - EIR
+ *                  eir_len - EIR len
+ *                  uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ *                              Uuid::kNumBytes128
+ *                  p_num_uuid - return number of UUID in found list
+ *                  p_uuid_list - return UUID list
+ *                  max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns          0 - if not found
+ *                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_16BITS_UUID_TYPE
+ *                  BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_32BITS_UUID_TYPE
+ *                  BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len,
+                                            uint8_t uuid_size,
+                                            uint8_t* p_num_uuid,
+                                            uint8_t* p_uuid_list,
+                                            uint8_t max_num_uuid) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_eir != nullptr);
+  CHECK(p_num_uuid != nullptr);
+  CHECK(p_uuid_list != nullptr);
+  return 0;
+}
+
+/**
+ *
+ * BLE API HERE
+ *
+ */
+
+bool bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr,
+                                          BD_NAME bd_name,
+                                          tBT_DEVICE_TYPE dev_type,
+                                          tBLE_ADDR_TYPE addr_type) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecAddBleKey
+ *
+ * Description      Add/modify LE device information.  This function will be
+ *                  normally called during host startup to restore all required
+ *                  information stored in the NVRAM.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  p_le_key         - LE key values.
+ *                  key_type         - LE SMP key type.
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_SecAddBleKey(const RawAddress& bd_addr,
+                                       tBTM_LE_KEY_VALUE* p_le_key,
+                                       tBTM_LE_KEY_TYPE key_type) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_le_key != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleLoadLocalKeys
+ *
+ * Description      Local local identity key, encryption root or sign counter.
+ *
+ * Parameters:      key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ *                                                BTM_BLE_KEY_TYPE_ER
+ *                                             or BTM_BLE_KEY_TYPE_COUNTER.
+ *                  p_key: pointer to the key.
+ *
+ * Returns          non2.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleLoadLocalKeys(uint8_t key_type,
+                                           tBTM_BLE_LOCAL_KEYS* p_key) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_key != nullptr);
+}
+
+static Octet16 bogus_root;
+
+/** Returns local device encryption root (ER) */
+const Octet16& bluetooth::shim::BTM_GetDeviceEncRoot() {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return bogus_root;
+}
+
+/** Returns local device identity root (IR). */
+const Octet16& bluetooth::shim::BTM_GetDeviceIDRoot() {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return bogus_root;
+}
+
+/** Return local device DHK. */
+const Octet16& bluetooth::shim::BTM_GetDeviceDHK() {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return bogus_root;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectionAddr
+ *
+ * Description      This function is called to get the local device address
+ *                  information.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_ReadConnectionAddr(const RawAddress& remote_bda,
+                                             RawAddress& local_conn_addr,
+                                             tBLE_ADDR_TYPE* p_addr_type) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_addr_type != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsBleConnection
+ *
+ * Description      This function is called to check if the connection handle
+ *                  for an LE link
+ *
+ * Returns          true if connection is LE link, otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_IsBleConnection(uint16_t conn_handle) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function       BTM_ReadRemoteConnectionAddr
+ *
+ * Description    This function is read the remote device address currently used
+ *
+ * Parameters     pseudo_addr: pseudo random address available
+ *                conn_addr:connection address used
+ *                p_addr_type : BD Address type, Public or Random of the address
+ *                              used
+ *
+ * Returns        bool, true if connection to remote device exists, else false
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_ReadRemoteConnectionAddr(
+    const RawAddress& pseudo_addr, RawAddress& conn_addr,
+    tBLE_ADDR_TYPE* p_addr_type) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_addr_type != nullptr);
+  return false;
+}
+/*******************************************************************************
+ *
+ * Function         BTM_SecurityGrant
+ *
+ * Description      This function is called to grant security process.
+ *
+ * Parameters       bd_addr - peer device bd address.
+ *                  res     - result of the operation BTM_SUCCESS if success.
+ *                            Otherwise, BTM_REPEATED_ATTEMPTS if too many
+ *                            attempts.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_SecurityGrant(const RawAddress& bd_addr,
+                                        uint8_t res) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BlePasskeyReply
+ *
+ * Description      This function is called after Security Manager submitted
+ *                  passkey request to the application.
+ *
+ * Parameters:      bd_addr - Address of the device for which passkey was
+ *                            requested
+ *                  res     - result of the operation BTM_SUCCESS if success
+ *                  key_len - length in bytes of the Passkey
+ *                  p_passkey    - pointer to array with the passkey
+ *                  trusted_mask - bitwise OR of trusted services (array of
+ *                                 uint32_t)
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BlePasskeyReply(const RawAddress& bd_addr,
+                                          uint8_t res, uint32_t passkey) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleConfirmReply
+ *
+ * Description      This function is called after Security Manager submitted
+ *                  numeric comparison request to the application.
+ *
+ * Parameters:      bd_addr      - Address of the device with which numeric
+ *                                 comparison was requested
+ *                  res          - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleConfirmReply(const RawAddress& bd_addr,
+                                          uint8_t res) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleOobDataReply
+ *
+ * Description      This function is called to provide the OOB data for
+ *                  SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters:      bd_addr     - Address of the peer device
+ *                  res         - result of the operation SMP_SUCCESS if success
+ *                  p_data      - oob data, depending on transport and
+ *                                capabilities.
+ *                                Might be "Simple Pairing Randomizer", or
+ *                                "Security Manager TK Value".
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleOobDataReply(const RawAddress& bd_addr,
+                                          uint8_t res, uint8_t len,
+                                          uint8_t* p_data) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_data != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSecureConnectionOobDataReply
+ *
+ * Description      This function is called to provide the OOB data for
+ *                  SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ *                  data is available
+ *
+ * Parameters:      bd_addr     - Address of the peer device
+ *                  p_c         - pointer to Confirmation.
+ *                  p_r         - pointer to Randomizer
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSecureConnectionOobDataReply(
+    const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_c != nullptr);
+  CHECK(p_r != nullptr);
+}
+
+/******************************************************************************
+ *
+ * Function         BTM_BleSetConnScanParams
+ *
+ * Description      Set scan parameter used in BLE connection request
+ *
+ * Parameters:      scan_interval: scan interval
+ *                  scan_window: scan window
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetConnScanParams(uint32_t scan_interval,
+                                               uint32_t scan_window) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/********************************************************
+ *
+ * Function         BTM_BleSetPrefConnParams
+ *
+ * Description      Set a peripheral's preferred connection parameters
+ *
+ * Parameters:      bd_addr          - BD address of the peripheral
+ *                  scan_interval: scan interval
+ *                  scan_window: scan window
+ *                  min_conn_int     - minimum preferred connection interval
+ *                  max_conn_int     - maximum preferred connection interval
+ *                  slave_latency    - preferred slave latency
+ *                  supervision_tout - preferred supervision timeout
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetPrefConnParams(const RawAddress& bd_addr,
+                                               uint16_t min_conn_int,
+                                               uint16_t max_conn_int,
+                                               uint16_t slave_latency,
+                                               uint16_t supervision_tout) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDevInfo
+ *
+ * Description      This function is called to read the device/address type
+ *                  of BD address.
+ *
+ * Parameter        remote_bda: remote device address
+ *                  p_dev_type: output parameter to read the device type.
+ *                  p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_ReadDevInfo(const RawAddress& remote_bda,
+                                      tBT_DEVICE_TYPE* p_dev_type,
+                                      tBLE_ADDR_TYPE* p_addr_type) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_dev_type != nullptr);
+  CHECK(p_addr_type != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectedTransportAddress
+ *
+ * Description      This function is called to read the paired device/address
+ *                  type of other device paired corresponding to the BD_address
+ *
+ * Parameter        remote_bda: remote device address, carry out the transport
+ *                              address
+ *                  transport: active transport
+ *
+ * Return           true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_ReadConnectedTransportAddress(
+    RawAddress* remote_bda, tBT_TRANSPORT transport) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(remote_bda != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleReceiverTest
+ *
+ * Description      This function is called to start the LE Receiver test
+ *
+ * Parameter       rx_freq - Frequency Range
+ *               p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleReceiverTest(uint8_t rx_freq,
+                                          tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleTransmitterTest
+ *
+ * Description      This function is called to start the LE Transmitter test
+ *
+ * Parameter       tx_freq - Frequency Range
+ *                       test_data_len - Length in bytes of payload data in each
+ *                                       packet
+ *                       packet_payload - Pattern to use in the payload
+ *                       p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleTransmitterTest(uint8_t tx_freq,
+                                             uint8_t test_data_len,
+                                             uint8_t packet_payload,
+                                             tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleTestEnd
+ *
+ * Description      This function is called to stop the in-progress TX or RX
+ *                  test
+ *
+ * Parameter       p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_UseLeLink
+ *
+ * Description      This function is to select the underlying physical link to
+ *                  use.
+ *
+ * Returns          true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_UseLeLink(const RawAddress& raw_address) {
+  return shim_btm.IsLeAclConnected(raw_address);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetBleDataLength
+ *
+ * Description      This function is to set maximum BLE transmission packet size
+ *
+ * Returns          BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetBleDataLength(const RawAddress& bd_addr,
+                                                  uint16_t tx_pdu_length) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleReadPhy
+ *
+ * Description      To read the current PHYs for specified LE connection
+ *
+ *
+ * Returns          BTM_SUCCESS if command successfully sent to controller,
+ *                  BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ *                  2M or LE Coded PHY,
+ *                  BTM_WRONG_MODE if Device in wrong mode for request.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleReadPhy(
+    const RawAddress& bd_addr,
+    base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetDefaultPhy
+ *
+ * Description      To set preferred PHY for ensuing LE connections
+ *
+ *
+ * Returns          BTM_SUCCESS if command successfully sent to controller,
+ *                  BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ *                  2M or LE Coded PHY
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_BleSetDefaultPhy(uint8_t all_phys,
+                                                  uint8_t tx_phys,
+                                                  uint8_t rx_phys) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetPhy
+ *
+ * Description      To set PHY preferences for specified LE connection
+ *
+ *
+ * Returns          BTM_SUCCESS if command successfully sent to controller,
+ *                  BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ *                  2M or LE Coded PHY,
+ *                  BTM_ILLEGAL_VALUE if specified remote doesn't support LE 2M
+ *                  or LE Coded PHY,
+ *                  BTM_WRONG_MODE if Device in wrong mode for request.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys,
+                                    uint8_t rx_phys, uint16_t phy_options) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleDataSignature
+ *
+ * Description      This function is called to sign the data using AES128 CMAC
+ *                  algorith.
+ *
+ * Parameter        bd_addr: target device the data to be signed for.
+ *                  p_text: singing data
+ *                  len: length of the data to be signed.
+ *                  signature: output parameter where data signature is going to
+ *                             be stored.
+ *
+ * Returns          true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleDataSignature(const RawAddress& bd_addr,
+                                           uint8_t* p_text, uint16_t len,
+                                           BLE_SIGNATURE signature) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_text != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleVerifySignature
+ *
+ * Description      This function is called to verify the data signature
+ *
+ * Parameter        bd_addr: target device the data to be signed for.
+ *                  p_orig:  original data before signature.
+ *                  len: length of the signing data
+ *                  counter: counter used when doing data signing
+ *                  p_comp: signature to be compared against.
+
+ * Returns          true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleVerifySignature(const RawAddress& bd_addr,
+                                             uint8_t* p_orig, uint16_t len,
+                                             uint32_t counter,
+                                             uint8_t* p_comp) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_orig != nullptr);
+  CHECK(p_comp != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetLeSecurityState
+ *
+ * Description      This function is called to get security mode 1 flags and
+ *                  encryption key size for LE peer.
+ *
+ * Returns          bool    true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_GetLeSecurityState(const RawAddress& bd_addr,
+                                             uint8_t* p_le_dev_sec_flags,
+                                             uint8_t* p_le_key_size) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  CHECK(p_le_dev_sec_flags != nullptr);
+  CHECK(p_le_key_size != nullptr);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSecurityProcedureIsRunning
+ *
+ * Description      This function indicates if LE security procedure is
+ *                  currently running with the peer.
+ *
+ * Returns          bool    true if security procedure is running, false
+ *                  otherwise.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleSecurityProcedureIsRunning(
+    const RawAddress& bd_addr) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleGetSupportedKeySize
+ *
+ * Description      This function gets the maximum encryption key size in bytes
+ *                  the local device can suport.
+ *                  record.
+ *
+ * Returns          the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+/**
+ * This function update(add,delete or clear) the adv local name filtering
+ * condition.
+ */
+void bluetooth::shim::BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+                                           tBTM_BLE_PF_FILT_INDEX filt_index,
+                                           std::vector<uint8_t> name,
+                                           tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+                                          tBTM_BLE_PF_FILT_INDEX filt_index) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_manu_data(
+    tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index,
+    uint16_t company_id, uint16_t company_id_mask, std::vector<uint8_t> data,
+    std::vector<uint8_t> data_mask, tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_srvc_data_pattern(
+    tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index,
+    std::vector<uint8_t> data, std::vector<uint8_t> data_mask,
+    tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+                                            tBTM_BLE_PF_FILT_INDEX filt_index,
+                                            tBLE_BD_ADDR addr,
+                                            tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+                                            tBTM_BLE_PF_FILT_INDEX filt_index,
+                                            tBTM_BLE_PF_COND_TYPE filter_type,
+                                            const bluetooth::Uuid& uuid,
+                                            tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+                                            const bluetooth::Uuid& uuid_mask,
+                                            tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+                                    std::vector<ApcfCommand> commands,
+                                    tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+                                      tBTM_BLE_PF_CFG_CBACK cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_BleAdvFilterParamSetup(
+    int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+    std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+    tBTM_BLE_PF_PARAM_CB cb) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_BleEnableDisableFilterFeature(
+    uint8_t enable, tBTM_BLE_PF_STATUS_CBACK p_stat_cback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
diff --git a/main/shim/btm_api.h b/main/shim/btm_api.h
new file mode 100644
index 0000000..6cd1fc4
--- /dev/null
+++ b/main/shim/btm_api.h
@@ -0,0 +1,2785 @@
+/*
+ * 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 "stack/include/btm_api_types.h"
+#include "stack/include/btm_ble_api_types.h"
+
+namespace bluetooth {
+namespace shim {
+
+/*******************************************************************************
+ *
+ * Function         BTM_DeviceReset
+ *
+ * Description      This function is called to reset the controller.  The
+ *                  Callback function if provided is called when startup of the
+ *                  device has completed.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_DeviceReset(tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsDeviceUp
+ *
+ * Description      This function is called to check if the device is up.
+ *
+ * Returns          true if device is up, else false
+ *
+ ******************************************************************************/
+bool BTM_IsDeviceUp(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetLocalDeviceName
+ *
+ * Description      This function is called to set the local device name.
+ *
+ * Returns          BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName(char* p_name);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDeviceClass
+ *
+ * Description      This function is called to set the local device class
+ *
+ * Returns          BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadLocalDeviceName
+ *
+ * Description      This function is called to read the local device name.
+ *
+ * Returns          status of the operation
+ *                  If success, BTM_SUCCESS is returned and p_name points stored
+ *                              local device name
+ *                  If BTM doesn't store local device name, BTM_NO_RESOURCES is
+ *                              is returned and p_name is set to NULL
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceName(char** p_name);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadLocalDeviceNameFromController
+ *
+ * Description      Get local device name from controller. Do not use cached
+ *                  name (used to get chip-id prior to btm reset complete).
+ *
+ * Returns          BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceNameFromController(
+    tBTM_CMPL_CB* p_rln_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDeviceClass
+ *
+ * Description      This function is called to read the local device class
+ *
+ * Returns          pointer to the device class
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadDeviceClass(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadLocalFeatures
+ *
+ * Description      This function is called to read the local features
+ *
+ * Returns          pointer to the local features string
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadLocalFeatures(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RegisterForDeviceStatusNotif
+ *
+ * Description      This function is called to register for device status
+ *                  change notifications.
+ *
+ * Returns          pointer to previous caller's callback function or NULL if
+ *                  first registration.
+ *
+ ******************************************************************************/
+tBTM_DEV_STATUS_CB* BTM_RegisterForDeviceStatusNotif(tBTM_DEV_STATUS_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RegisterForVSEvents
+ *
+ * Description      This function is called to register/deregister for vendor
+ *                  specific HCI events.
+ *
+ *                  If is_register=true, then the function will be registered;
+ *                  otherwise the function will be deregistered.
+ *
+ * Returns          BTM_SUCCESS if successful,
+ *                  BTM_BUSY if maximum number of callbacks have already been
+ *                           registered.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register);
+
+/*******************************************************************************
+ *
+ * Function         BTM_VendorSpecificCommand
+ *
+ * Description      Send a vendor specific HCI command to the controller.
+ *
+ ******************************************************************************/
+void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len,
+                               uint8_t* p_param_buf, tBTM_VSC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_AllocateSCN
+ *
+ * Description      Look through the Server Channel Numbers for a free one to be
+ *                  used with an RFCOMM connection.
+ *
+ * Returns          Allocated SCN number or 0 if none.
+ *
+ ******************************************************************************/
+uint8_t BTM_AllocateSCN(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_TryAllocateSCN
+ *
+ * Description      Try to allocate a fixed server channel
+ *
+ * Returns          Returns true if server channel was available
+ *
+ ******************************************************************************/
+bool BTM_TryAllocateSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function         BTM_FreeSCN
+ *
+ * Description      Free the specified SCN.
+ *
+ * Returns          true if successful, false if SCN is not in use or invalid
+ *
+ ******************************************************************************/
+bool BTM_FreeSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetTraceLevel
+ *
+ * Description      This function sets the trace level for BTM.  If called with
+ *                  a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns          The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t BTM_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function         BTM_WritePageTimeout
+ *
+ * Description      Send HCI Wite Page Timeout.
+ *
+ ******************************************************************************/
+void BTM_WritePageTimeout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function         BTM_WriteVoiceSettings
+ *
+ * Description      Send HCI Write Voice Settings command.
+ *                  See hcidefs.h for settings bitmask values.
+ *
+ ******************************************************************************/
+void BTM_WriteVoiceSettings(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function         BTM_EnableTestMode
+ *
+ * Description      Send HCI the enable device under test command.
+ *
+ *                  Note: Controller can only be taken out of this mode by
+ *                      resetting the controller.
+ *
+ * Returns
+ *      BTM_SUCCESS         Command sent.
+ *      BTM_NO_RESOURCES    If out of resources to send the command.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_EnableTestMode(void);
+
+/*******************************************************************************
+ * DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDiscoverability
+ *
+ * Description      This function is called to set the device into or out of
+ *                  discoverable mode. Discoverable mode means inquiry
+ *                  scans are enabled.  If a value of '0' is entered for window
+ *                  or interval, the default values are used.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_BUSY if a setting of the filter is already in progress
+ *                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ *                  BTM_ILLEGAL_VALUE if a bad parameter was detected
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
+                                   uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDiscoverability
+ *
+ * Description      This function is called to read the current discoverability
+ *                  mode of the device.
+ *
+ * Output Params:   p_window - current inquiry scan duration
+ *                  p_interval - current inquiry scan interval
+ *
+ * Returns          BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ *                  BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPeriodicInquiryMode
+ *
+ * Description      This function is called to set the device periodic inquiry
+ *                  mode. If the duration is zero, the periodic inquiry mode is
+ *                  cancelled.
+ *
+ * Parameters:      p_inqparms - pointer to the inquiry information
+ *                      mode - GENERAL or LIMITED inquiry
+ *                      duration - length in 1.28 sec intervals (If '0', the
+ *                                 inquiry is CANCELLED)
+ *                      max_resps - maximum amount of devices to search for
+ *                                  before ending the inquiry
+ *                      filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ *                                         BTM_FILTER_COND_DEVICE_CLASS, or
+ *                                         BTM_FILTER_COND_BD_ADDR
+ *                      filter_cond - value for the filter (based on
+ *                                                          filter_cond_type)
+ *
+ *                  max_delay - maximum amount of time between successive
+ *                              inquiries
+ *                  min_delay - minimum amount of time between successive
+ *                              inquiries
+ *                  p_results_cb - callback returning pointer to results
+ *                              (tBTM_INQ_RESULTS)
+ *
+ * Returns          BTM_CMD_STARTED if successfully started
+ *                  BTM_ILLEGAL_VALUE if a bad parameter is detected
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_SUCCESS - if cancelling the periodic inquiry
+ *                  BTM_BUSY - if an inquiry is already active
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS* p_inqparms,
+                                       uint16_t max_delay, uint16_t min_delay,
+                                       tBTM_INQ_RESULTS_CB* p_results_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_StartInquiry
+ *
+ * Description      This function is called to start an inquiry.
+ *
+ * Parameters:      p_inqparms - pointer to the inquiry information
+ *                      mode - GENERAL or LIMITED inquiry
+ *                      duration - length in 1.28 sec intervals (If '0', the
+ *                                 inquiry is CANCELLED)
+ *                      max_resps - maximum amount of devices to search for
+ *                                  before ending the inquiry
+ *                      filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ *                                         BTM_FILTER_COND_DEVICE_CLASS, or
+ *                                         BTM_FILTER_COND_BD_ADDR
+ *                      filter_cond - value for the filter (based on
+ *                                                          filter_cond_type)
+ *
+ *                  p_results_cb  - Pointer to the callback routine which gets
+ *                                called upon receipt of an inquiry result. If
+ *                                this field is NULL, the application is not
+ *                                notified.
+ *
+ *                  p_cmpl_cb   - Pointer to the callback routine which gets
+ *                                called upon completion.  If this field is
+ *                                NULL, the application is not notified when
+ *                                completed.
+ * Returns          tBTM_STATUS
+ *                  BTM_CMD_STARTED if successfully initiated
+ *                  BTM_BUSY if already in progress
+ *                  BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ *                  BTM_NO_RESOURCES if could not allocate resources to start
+ *                                   the command
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+                             tBTM_INQ_RESULTS_CB* p_results_cb,
+                             tBTM_CMPL_CB* p_cmpl_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsInquiryActive
+ *
+ * Description      Return a bit mask of the current inquiry state
+ *
+ * Returns          BTM_INQUIRY_INACTIVE if inactive (0)
+ *                  BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ *                  BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ *                  BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+uint16_t BTM_IsInquiryActive(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelInquiry
+ *
+ * Description      This function cancels an inquiry if active
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelPeriodicInquiry
+ *
+ * Description      This function cancels a periodic inquiry
+ *
+ * Returns
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_SUCCESS - if cancelling the periodic inquiry
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelPeriodicInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetConnectability
+ *
+ * Description      This function is called to set the device into or out of
+ *                  connectable mode. Discoverable mode means page scans are
+ *                  enabled.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_ILLEGAL_VALUE if a bad parameter is detected
+ *                  BTM_NO_RESOURCES if could not allocate a message buffer
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
+                                  uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectability
+ *
+ * Description      This function is called to read the current discoverability
+ *                  mode of the device.
+ * Output Params    p_window - current page scan duration
+ *                  p_interval - current time between page scans
+ *
+ * Returns          BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadConnectability(uint16_t* p_window, uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetInquiryMode
+ *
+ * Description      This function is called to set standard, with RSSI
+ *                  mode or extended of the inquiry for local device.
+ *
+ * Input Params:    BTM_INQ_RESULT_STANDARD, BTM_INQ_RESULT_WITH_RSSI or
+ *                  BTM_INQ_RESULT_EXTENDED
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ *                  BTM_ILLEGAL_VALUE if a bad parameter was detected
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryMode(uint8_t mode);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetInquiryScanType
+ *
+ * Description      This function is called to set the iquiry scan-type to
+ *                  standard or interlaced.
+ *
+ * Input Params:    BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_MODE_UNSUPPORTED if not a 1.2 device
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPageScanType
+ *
+ * Description      This function is called to set the page scan-type to
+ *                  standard or interlaced.
+ *
+ * Input Params:    BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns          BTM_SUCCESS if successful
+ *                  BTM_MODE_UNSUPPORTED if not a 1.2 device
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+
+tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteDeviceName
+ *
+ * Description      This function initiates a remote device HCI command to the
+ *                  controller and calls the callback when the process has
+ *                  completed.
+ *
+ * Input Params:    remote_bda      - device address of name to retrieve
+ *                  p_cb            - callback function called when
+ *                                    BTM_CMD_STARTED is returned.
+ *                                    A pointer to tBTM_REMOTE_DEV_NAME is
+ *                                    passed to the callback.
+ *
+ * Returns
+ *                  BTM_CMD_STARTED is returned if the request was successfully
+ *                                  sent to HCI.
+ *                  BTM_BUSY if already in progress
+ *                  BTM_UNKNOWN_ADDR if device address is bad
+ *                  BTM_NO_RESOURCES if resources could not be allocated to
+ *                                   start the command
+ *                  BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
+                                     tBTM_CMPL_CB* p_cb,
+                                     tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTM_CancelRemoteDeviceName
+ *
+ * Description      This function initiates the cancel request for the specified
+ *                  remote device.
+ *
+ * Input Params:    None
+ *
+ * Returns
+ *                  BTM_CMD_STARTED is returned if the request was successfully
+ *                                  sent to HCI.
+ *                  BTM_NO_RESOURCES if resources could not be allocated to
+ *                                   start the command
+ *                  BTM_WRONG_MODE if there is no active remote name request.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelRemoteDeviceName(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteVersion
+ *
+ * Description      This function is called to read a remote device's version
+ *
+ * Returns          BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version,
+                                  uint16_t* manufacturer,
+                                  uint16_t* lmp_sub_version);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteFeatures
+ *
+ * Description      This function is called to read a remote device's
+ *                  supported features mask (features mask located at page 0)
+ *
+ *                  Note: The size of device features mask page is
+ *                  BTM_FEATURE_BYTES_PER_PAGE bytes.
+ *
+ * Returns          pointer to the remote supported features mask
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteExtendedFeatures
+ *
+ * Description      This function is called to read a specific extended features
+ *                  page of the remote device
+ *
+ *                  Note1: The size of device features mask page is
+ *                  BTM_FEATURE_BYTES_PER_PAGE bytes.
+ *                  Note2: The valid device features mask page number depends on
+ *                  the remote device capabilities. It is expected to be in the
+ *                  range [0 - BTM_EXT_FEATURES_PAGE_MAX].
+
+ * Returns          pointer to the remote extended features mask
+ *                  or NULL if page_number is not valid
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteExtendedFeatures(const RawAddress& addr,
+                                        uint8_t page_number);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadNumberRemoteFeaturesPages
+ *
+ * Description      This function is called to retrieve the number of feature
+ *                  pages read from the remote device
+ *
+ * Returns          number of features pages read from the remote device
+ *
+ ******************************************************************************/
+uint8_t BTM_ReadNumberRemoteFeaturesPages(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadAllRemoteFeatures
+ *
+ * Description      Read all the features of the remote device
+ *
+ * Returns          pointer to the byte[0] of the page[0] of the remote device
+ *                  feature mask.
+ *
+ * Note:            the function returns the pointer to the array of the size
+ *                  BTM_FEATURE_BYTES_PER_PAGE * (BTM_EXT_FEATURES_PAGE_MAX + 1)
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadAllRemoteFeatures(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbRead
+ *
+ * Description      This function looks through the inquiry database for a match
+ *                  based on Bluetooth Device Address. This is the application's
+ *                  interface to get the inquiry details of a specific BD
+ *                  address.
+ *
+ * Returns          pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbRead(const RawAddress& p_bda);
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbFirst
+ *
+ * Description      This function looks through the inquiry database for the
+ *                  first used entry, and returns that. This is used in
+ *                  conjunction with BTM_InqDbNext by applications as a way to
+ *                  walk through the inquiry database.
+ *
+ * Returns          pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbFirst(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_InqDbNext
+ *
+ * Description      This function looks through the inquiry database for the
+ *                  next used entry, and returns that.  If the input parameter
+ *                  is NULL, the first entry is returned.
+ *
+ * Returns          pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ClearInqDb
+ *
+ * Description      This function is called to clear out a device or all devices
+ *                  from the inquiry database.
+ *
+ * Parameter        p_bda - (input) BD_ADDR ->  Address of device to clear
+ *                                              (NULL clears all entries)
+ *
+ * Returns          BTM_BUSY if an inquiry, get remote name, or event filter
+ *                          is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadInquiryRspTxPower
+ *
+ * Description      This command will read the inquiry Transmit Power level used
+ *                  to transmit the FHS and EIR data packets.
+ *                  This can be used directly in the Tx Power Level EIR data
+ *                  type.
+ *
+ * Returns          BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb);
+
+/*****************************************************************************
+ *  ACL CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTM_SetLinkPolicy
+ *
+ * Description      Create and send HCI "Write Policy Set" command
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy(const RawAddress& remote_bda, uint16_t* settings);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDefaultLinkPolicy
+ *
+ * Description      Set the default value for HCI "Write Policy Set" command
+ *                  to use when an ACL link is created.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkPolicy(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetDefaultLinkSuperTout
+ *
+ * Description      Set the default value for HCI "Write Link Supervision
+ *                  Timeout" command to use when an ACL link is created.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkSuperTout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetLinkSuperTout
+ *
+ * Description      Create and send HCI "Write Link Supervision Timeout" command
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
+                                 uint16_t timeout);
+/*******************************************************************************
+ *
+ * Function         BTM_GetLinkSuperTout
+ *
+ * Description      Read the link supervision timeout value of the connection
+ *
+ * Returns          status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
+                                 uint16_t* p_timeout);
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsAclConnectionUp
+ *
+ * Description      This function is called to check if an ACL connection exists
+ *                  to a specific remote BD Address.
+ *
+ * Returns          true if connection is up, else false.
+ *
+ ******************************************************************************/
+bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
+                           tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetRole
+ *
+ * Description      This function is called to get the role of the local device
+ *                  for the ACL connection with the specified remote device
+ *
+ * Returns          BTM_SUCCESS if connection exists.
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, uint8_t* p_role);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SwitchRole
+ *
+ * Description      This function is called to switch role between master and
+ *                  slave.  If role is already set it will do nothing.  If the
+ *                  command was initiated, the callback function is called upon
+ *                  completion.
+ *
+ * Returns          BTM_SUCCESS if already in specified role.
+ *                  BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_MODE_UNSUPPORTED if the local device does not support
+ *                                       role switching
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SwitchRole(const RawAddress& remote_bd_addr, uint8_t new_role,
+                           tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRSSI
+ *
+ * Description      This function is called to read the link policy settings.
+ *                  The address of link policy results are returned in the
+ *                  callback. (tBTM_RSSI_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadFailedContactCounter
+ *
+ * Description      This function is called to read the failed contact counter.
+ *                  The result is returned in the callback.
+ *                  (tBTM_FAILED_CONTACT_COUNTER_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadFailedContactCounter(const RawAddress& remote_bda,
+                                         tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadAutomaticFlushTimeout
+ *
+ * Description      This function is called to read the automatic flush timeout.
+ *                  The result is returned in the callback.
+ *                  (tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadAutomaticFlushTimeout(const RawAddress& remote_bda,
+                                          tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadTxPower
+ *
+ * Description      This function is called to read the current connection
+ *                  TX power of the connection. The TX power level results
+ *                  are returned in the callback.
+ *                  (tBTM_RSSI_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda,
+                            tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadLinkQuality
+ *
+ * Description      This function is called to read the link quality.
+ *                  The value of the link quality is returned in the callback.
+ *                  (tBTM_LINK_QUALITY_RESULT)
+ *
+ * Returns          BTM_CMD_STARTED if command issued to controller.
+ *                  BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ *                                   the command
+ *                  BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *                  BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality(const RawAddress& remote_bda,
+                                tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RegBusyLevelNotif
+ *
+ * Description      This function is called to register a callback to receive
+ *                  busy level change events.
+ *
+ * Returns          BTM_SUCCESS if successfully registered, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegBusyLevelNotif(tBTM_BL_CHANGE_CB* p_cb, uint8_t* p_level,
+                                  tBTM_BL_EVENT_MASK evt_mask);
+
+/*******************************************************************************
+ *
+ * Function         BTM_AclRegisterForChanges
+ *
+ * Description      This function is called to register a callback to receive
+ *                  ACL database change events, i.e. new connection or removed.
+ *
+ * Returns          BTM_SUCCESS if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_AclRegisterForChanges(tBTM_ACL_DB_CHANGE_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetNumAclLinks
+ *
+ * Description      This function is called to count the number of
+ *                  ACL links that are active.
+ *
+ * Returns          uint16_t Number of active ACL links
+ *
+ ******************************************************************************/
+uint16_t BTM_GetNumAclLinks(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetQoS
+ *
+ * Description      This function is called to setup QoS
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetQoS(const RawAddress& bd, FLOW_SPEC* p_flow,
+                       tBTM_CMPL_CB* p_cb);
+
+/*****************************************************************************
+ *  (e)SCO CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTM_CreateSco
+ *
+ * Description      This function is called to create an SCO connection. If the
+ *                  "is_orig" flag is true, the connection will be originated,
+ *                  otherwise BTM will wait for the other side to connect.
+ *
+ * Returns          BTM_UNKNOWN_ADDR if the ACL connection is not up
+ *                  BTM_BUSY         if another SCO being set up to
+ *                                   the same BD address
+ *                  BTM_NO_RESOURCES if the max SCO limit has been reached
+ *                  BTM_CMD_STARTED  if the connection establishment is started.
+ *                                   In this case, "*p_sco_inx" is filled in
+ *                                   with the sco index used for the connection.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig,
+                          uint16_t pkt_types, uint16_t* p_sco_inx,
+                          tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RemoveSco
+ *
+ * Description      This function is called to remove a specific SCO connection.
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetScoPacketTypes
+ *
+ * Description      This function is called to set the packet types used for
+ *                  a specific SCO connection,
+ *
+ * Parameters       pkt_types - One or more of the following
+ *                  BTM_SCO_PKT_TYPES_MASK_HV1
+ *                  BTM_SCO_PKT_TYPES_MASK_HV2
+ *                  BTM_SCO_PKT_TYPES_MASK_HV3
+ *                  BTM_SCO_PKT_TYPES_MASK_EV3
+ *                  BTM_SCO_PKT_TYPES_MASK_EV4
+ *                  BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ *                  BTM_SCO_LINK_ALL_MASK   - enables all supported types
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadScoPacketTypes
+ *
+ * Description      This function is read the packet types used for a specific
+ *                  SCO connection.
+ *
+ * Returns       One or more of the following (bitmask)
+ *                  BTM_SCO_PKT_TYPES_MASK_HV1
+ *                  BTM_SCO_PKT_TYPES_MASK_HV2
+ *                  BTM_SCO_PKT_TYPES_MASK_HV3
+ *                  BTM_SCO_PKT_TYPES_MASK_EV3
+ *                  BTM_SCO_PKT_TYPES_MASK_EV4
+ *                  BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ * Returns          packet types supported for the connection
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDeviceScoPacketTypes
+ *
+ * Description      This function is read the SCO packet types that
+ *                  the device supports.
+ *
+ * Returns          packet types supported by the device.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDeviceScoPacketTypes(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadScoHandle
+ *
+ * Description      Reead the HCI handle used for a specific SCO connection,
+ *
+ * Returns          handle for the connection, or 0xFFFF if invalid SCO index.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoHandle(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadScoBdAddr
+ *
+ * Description      This function is read the remote BD Address for a specific
+ *                  SCO connection,
+ *
+ * Returns          pointer to BD address or NULL if not known
+ *
+ ******************************************************************************/
+const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadScoDiscReason
+ *
+ * Description      This function is returns the reason why an (e)SCO connection
+ *                  has been removed. It contains the value until read, or until
+ *                  another (e)SCO connection has disconnected.
+ *
+ * Returns          HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoDiscReason(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetEScoMode
+ *
+ * Description      This function sets up the negotiated parameters for SCO or
+ *                  eSCO, and sets as the default mode used for calls to
+ *                  BTM_CreateSco.  It can be called only when there are no
+ *                  active (e)SCO links.
+ *
+ * Returns          BTM_SUCCESS if the successful.
+ *                  BTM_BUSY if there are one or more active (e)SCO links.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetWBSCodec
+ *
+ * Description      This function sends command to the controller to setup
+ *                  WBS codec for the upcoming eSCO connection.
+ *
+ * Returns          BTM_SUCCESS.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetWBSCodec(tBTM_SCO_CODEC_TYPE codec_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RegForEScoEvts
+ *
+ * Description      This function registers a SCO event callback with the
+ *                  specified instance.  It should be used to received
+ *                  connection indication events and change of link parameter
+ *                  events.
+ *
+ * Returns          BTM_SUCCESS if the successful.
+ *                  BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx, tBTM_ESCO_CBACK* p_esco_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadEScoLinkParms
+ *
+ * Description      This function returns the current eSCO link parameters for
+ *                  the specified handle.  This can be called anytime a
+ *                  connection is active, but is typically called after
+ *                  receiving the SCO opened callback.
+ *
+ *                  Note: If called over a 1.1 controller, only the packet types
+ *                        field has meaning.
+ *                  Note: If the upper layer doesn't know the current sco index,
+ *                  BTM_FIRST_ACTIVE_SCO_INDEX can be used as the first
+ *                  parameter to find the first active SCO index
+ *
+ * Returns          BTM_SUCCESS if returned data is valid connection.
+ *                  BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ *                  BTM_MODE_UNSUPPORTED if local controller does not support
+ *                      1.2 specification.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx, tBTM_ESCO_DATA* p_parms);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ChangeEScoLinkParms
+ *
+ * Description      This function requests renegotiation of the parameters on
+ *                  the current eSCO Link.  If any of the changes are accepted
+ *                  by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+ *                  the tBTM_ESCO_CBACK function with the current settings of
+ *                  the link. The callback is registered through the call to
+ *                  BTM_SetEScoMode.
+ *
+ *
+ * Returns          BTM_CMD_STARTED if command is successfully initiated.
+ *                  BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ *                  BTM_NO_RESOURCES - not enough resources to initiate command.
+ *                  BTM_MODE_UNSUPPORTED if local controller does not support
+ *                      1.2 specification.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
+                                    tBTM_CHG_ESCO_PARAMS* p_parms);
+
+/*******************************************************************************
+ *
+ * Function         BTM_EScoConnRsp
+ *
+ * Description      This function is called upon receipt of an (e)SCO connection
+ *                  request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+ *                  the request. Parameters used to negotiate eSCO links.
+ *                  If p_parms is NULL, then values set through BTM_SetEScoMode
+ *                  are used.
+ *                  If the link type of the incoming request is SCO, then only
+ *                  the tx_bw, max_latency, content format, and packet_types are
+ *                  valid.  The hci_status parameter should be
+ *                  ([0x0] to accept, [0x0d..0x0f] to reject)
+ *
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
+                     enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetNumScoLinks
+ *
+ * Description      This function returns the number of active SCO links.
+ *
+ * Returns          uint8_t
+ *
+ ******************************************************************************/
+uint8_t BTM_GetNumScoLinks(void);
+
+/*****************************************************************************
+ *  SECURITY MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTM_SecRegister
+ *
+ * Description      Application manager calls this function to register for
+ *                  security services.  There can be one and only one
+ *                  application saving link keys.  BTM allows only first
+ *                  registration.
+ *
+ * Returns          true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecRegisterLinkKeyNotificationCallback
+ *
+ * Description      Profiles can register to be notified when a new Link Key
+ *                  is generated per connection.
+ *
+ * Returns          true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegisterLinkKeyNotificationCallback(
+    tBTM_LINK_KEY_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecAddRmtNameNotifyCallback
+ *
+ * Description      Profiles can register to be notified when name of the
+ *                  remote device is resolved (up to
+ *                  BTM_SEC_MAX_RMT_NAME_CALLBACKS).
+ *
+ * Returns          true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecDeleteRmtNameNotifyCallback
+ *
+ * Description      A profile can deregister notification when a new Link Key
+ *                  is generated per connection.
+ *
+ * Returns          true if OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetSecurityFlags
+ *
+ * Description      Get security flags for the device
+ *
+ * Returns          bool    true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlags(const RawAddress& bd_addr, uint8_t* p_sec_flags);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetSecurityFlagsByTransport
+ *
+ * Description      Get security flags for the device on a particular transport
+ *
+ * Parameters      bd_addr: BD address of remote device
+ *                  p_sec_flags : Out parameter to be filled with security
+ *                                flags for the connection
+ *                  transport :  Physical transport of the connection
+ *                               (BR/EDR or LE)
+ *
+ * Returns          bool    true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr,
+                                     uint8_t* p_sec_flags,
+                                     tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadTrustedMask
+ *
+ * Description      Get trusted mask for the device
+ *
+ * Returns          NULL, if the device record is not found.
+ *                  otherwise, the trusted mask
+ *
+ ******************************************************************************/
+uint32_t* BTM_ReadTrustedMask(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPinType
+ *
+ * Description      Set PIN type for the device.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPairableMode
+ *
+ * Description      Enable or disable pairing
+ *
+ * Parameters       allow_pairing - (true or false) whether or not the device
+ *                      allows pairing.
+ *                  connect_only_paired - (true or false) whether or not to
+ *                      only allow paired devices to connect.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetPairableMode(bool allow_pairing, bool connect_only_paired);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetSecureConnectionsOnly
+ *
+ * Description      Enable or disable default treatment for Mode 4 Level 0
+ *                  services
+ *
+ * Parameter        secure_connections_only_mode - (true or false)
+ *                  true means that the device should treat Mode 4 Level 0
+ *                  services as services of other levels.
+ *                  false means that the device should provide default
+ *                  treatment for Mode 4 Level 0 services.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetSecureConnectionsOnly(bool secure_connections_only_mode);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetSecurityLevel
+ *
+ * Description      Register service security level with Security Manager.  Each
+ *                  service must register its requirements regardless of the
+ *                  security level that is used.  This API is called once for
+ *                  originators and again for acceptors of connections.
+ *
+ * Returns          true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
+                          uint8_t service_id, uint16_t sec_level, uint16_t psm,
+                          uint32_t mx_proto_id, uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetOutService
+ *
+ * Description      This function is called to set the service for
+ *                  outgoing connection.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetOutService(const RawAddress& bd_addr, uint8_t service_id,
+                       uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecClrService
+ *
+ * Description      Removes specified service record(s) from the security
+ *                  database. All service records with the specified name are
+ *                  removed. Typically used only by devices with limited RAM
+ *                  so that it can reuse an old security service record.
+ *
+ * Returns          Number of records that were freed.
+ *
+ ******************************************************************************/
+uint8_t BTM_SecClrService(uint8_t service_id);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecAddDevice
+ *
+ * Description      Add/modify device.  This function will be normally called
+ *                  during host startup to restore all required information
+ *                  stored in the NVRAM.
+ *                  dev_class, bd_name, link_key, and features are NULL if
+ *                  unknown
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
+                      BD_NAME bd_name, uint8_t* features,
+                      uint32_t trusted_mask[], LinkKey* link_key,
+                      uint8_t key_type, tBTM_IO_CAP io_cap, uint8_t pin_length);
+
+/** Free resources associated with the device associated with |bd_addr| address.
+ *
+ * *** WARNING ***
+ * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
+ * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
+ * no longer valid!
+ * *** WARNING ***
+ *
+ * Returns true if removed OK, false if not found or ACL link is active.
+ */
+bool BTM_SecDeleteDevice(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecClearSecurityFlags
+ *
+ * Description      Reset the security flags (mark as not-paired) for a given
+ *                  remove device.
+ *
+ ******************************************************************************/
+void BTM_SecClearSecurityFlags(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecGetDeviceLinkKey
+ *
+ * Description      This function is called to obtain link key for the device
+ *                  it returns BTM_SUCCESS if link key is available, or
+ *                  BTM_UNKNOWN_ADDR if Security Manager does not know about
+ *                  the device or device record does not contain link key info
+ *
+ * Returns          BTM_SUCCESS if successful, otherwise error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
+                                    LinkKey* link_key);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecGetDeviceLinkKeyType
+ *
+ * Description      This function is called to obtain link key type for the
+ *                  device.
+ *                  it returns BTM_SUCCESS if link key is available, or
+ *                  BTM_UNKNOWN_ADDR if Security Manager does not know about
+ *                  the device or device record does not contain link key info
+ *
+ * Returns          BTM_LKEY_TYPE_IGNORE if link key is unknown, link type
+ *                  otherwise.
+ *
+ ******************************************************************************/
+tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_PINCodeReply
+ *
+ * Description      This function is called after Security Manager submitted
+ *                  PIN code request to the UI.
+ *
+ * Parameters:      bd_addr      - Address of the device for which PIN was
+ *                                 requested
+ *                  res          - result of the operation BTM_SUCCESS if
+ *                                 success
+ *                  pin_len      - length in bytes of the PIN Code
+ *                  p_pin        - pointer to array with the PIN Code
+ *                  trusted_mask - bitwise OR of trusted services
+ *                                 (array of uint32_t)
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_PINCodeReply(const RawAddress& bd_addr, uint8_t res, uint8_t pin_len,
+                      uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecBond
+ *
+ * Description      This function is called to perform bonding with peer device.
+ *
+ * Parameters:      bd_addr      - Address of the device to bond
+ *                  pin_len      - length in bytes of the PIN Code
+ *                  p_pin        - pointer to array with the PIN Code
+ *                  trusted_mask - bitwise OR of trusted services
+ *                                 (array of uint32_t)
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, uint8_t pin_len,
+                        uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecBondByTransport
+ *
+ * Description      Perform bonding by designated transport
+ *
+ * Parameters:      bd_addr      - Address of the device to bond
+ *                  pin_len      - length in bytes of the PIN Code
+ *                  p_pin        - pointer to array with the PIN Code
+ *                  trusted_mask - bitwise OR of trusted services
+ *                                 (array of uint32_t)
+ *                  transport :  Physical transport to use for bonding
+ *                               (BR/EDR or LE)
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondByTransport(const RawAddress& bd_addr,
+                                   tBT_TRANSPORT transport, uint8_t pin_len,
+                                   uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecBondCancel
+ *
+ * Description      This function is called to cancel ongoing bonding process
+ *                  with peer device.
+ *
+ * Returns          BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetEncryption
+ *
+ * Description      This function is called to ensure that connection is
+ *                  encrypted.  Should be called only on an open connection.
+ *                  Typically only needed for connections that first want to
+ *                  bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters:      bd_addr       - Address of the peer device
+ *                  transport     - Link transport
+ *                  p_callback    - Pointer to callback function called if
+ *                                  this function returns PENDING after required
+ *                                  procedures are completed.  Can be set to
+ *                                  NULL if status is not desired.
+ *                  p_ref_data    - pointer to any data the caller wishes to
+ *                                  receive in the callback function upon
+ *                                  completion.
+ *                                  can be set to NULL if not used.
+ *                  sec_act       - LE security action, unused for BR/EDR
+ *
+ * Returns          BTM_SUCCESS   - already encrypted
+ *                  BTM_PENDING   - command will be returned in the callback
+ *                  BTM_WRONG_MODE- connection not up.
+ *                  BTM_BUSY      - security procedures are currently active
+ *                  BTM_MODE_UNSUPPORTED - if security manager not linked in.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr,
+                              tBT_TRANSPORT transport,
+                              tBTM_SEC_CBACK* p_callback, void* p_ref_data,
+                              tBTM_BLE_SEC_ACT sec_act);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ConfirmReqReply
+ *
+ * Description      This function is called to confirm the numeric value for
+ *                  Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+ *
+ * Parameters:      res           - result of the operation BTM_SUCCESS if
+ *                                  success
+ *                  bd_addr       - Address of the peer device
+ *
+ ******************************************************************************/
+void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_PasskeyReqReply
+ *
+ * Description      This function is called to provide the passkey for
+ *                  Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+ *
+ * Parameters:      res           - result of the operation BTM_SUCCESS if
+ *                                  success
+ *                  bd_addr       - Address of the peer device
+ *                  passkey       - numeric value in the range of
+ *                                  0 - 999999(0xF423F).
+ *
+ ******************************************************************************/
+void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
+                         uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SendKeypressNotif
+ *
+ * Description      This function is used during the passkey entry model
+ *                  by a device with KeyboardOnly IO capabilities
+ *                  (very likely to be a HID Device).
+ *                  It is called by a HID Device to inform the remote device
+ *                  when a key has been entered or erased.
+ *
+ * Parameters:      bd_addr - Address of the peer device
+ *                  type - notification type
+ *
+ ******************************************************************************/
+void BTM_SendKeypressNotif(const RawAddress& bd_addr, tBTM_SP_KEY_TYPE type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_IoCapRsp
+ *
+ * Description      This function is called in response to BTM_SP_IO_REQ_EVT
+ *                  When the event data io_req.oob_data is set to
+ *                  BTM_OOB_UNKNOWN by the tBTM_SP_CALLBACK implementation, this
+ *                  function is called to provide the actual response
+ *
+ * Parameters:      bd_addr - Address of the peer device
+ *                  io_cap  - The IO capability of local device.
+ *                  oob     - BTM_OOB_NONE or BTM_OOB_PRESENT.
+ *                  auth_req- MITM protection required or not.
+ *
+ ******************************************************************************/
+void BTM_IoCapRsp(const RawAddress& bd_addr, tBTM_IO_CAP io_cap,
+                  tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadLocalOobData
+ *
+ * Description      This function is called to read the local OOB data from
+ *                  LM
+ *
+ ******************************************************************************/
+void BTM_ReadLocalOobData(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RemoteOobDataReply
+ *
+ * Description      This function is called to provide the remote OOB data for
+ *                  Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+ *
+ * Parameters:      bd_addr     - Address of the peer device
+ *                  c           - simple pairing Hash C.
+ *                  r           - simple pairing Randomizer  C.
+ *
+ ******************************************************************************/
+void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
+                            const Octet16& c, const Octet16& r);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BuildOobData
+ *
+ * Description      This function is called to build the OOB data payload to
+ *                  be sent over OOB (non-Bluetooth) link
+ *
+ * Parameters:      p_data  - the location for OOB data
+ *                  max_len - p_data size.
+ *                  c       - simple pairing Hash C.
+ *                  r       - simple pairing Randomizer  C.
+ *                  name_len- 0, local device name would not be included.
+ *                            otherwise, the local device name is included for
+ *                            up to this specified length
+ *
+ * Returns          Number of bytes in p_data.
+ *
+ ******************************************************************************/
+uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, const Octet16& c,
+                          const Octet16& r, uint8_t name_len);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BothEndsSupportSecureConnections
+ *
+ * Description      This function is called to check if both the local device
+ *                  and the peer device specified by bd_addr support BR/EDR
+ *                  Secure Connections.
+ *
+ * Parameters:      bd_addr - address of the peer
+ *
+ * Returns          true if BR/EDR Secure Connections are supported by both
+ *                  local and the remote device.
+ *                  else false.
+ *
+ ******************************************************************************/
+bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_PeerSupportsSecureConnections
+ *
+ * Description      This function is called to check if the peer supports
+ *                  BR/EDR Secure Connections.
+ *
+ * Parameters:      bd_addr - address of the peer
+ *
+ * Returns          true if BR/EDR Secure Connections are supported by the peer,
+ *                  else false.
+ *
+ ******************************************************************************/
+bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadOobData
+ *
+ * Description      This function is called to parse the OOB data payload
+ *                  received over OOB (non-Bluetooth) link
+ *
+ * Parameters:      p_data  - the location for OOB data
+ *                  eir_tag - The associated EIR tag to read the data.
+ *                  *p_len(output) - the length of the data with the given tag.
+ *
+ * Returns          the beginning of the data with the given tag.
+ *                  NULL, if the tag is not found.
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadOobData(uint8_t* p_data, uint8_t eir_tag, uint8_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecReadDevName
+ *
+ * Description      Looks for the device name in the security database for the
+ *                  specified BD address.
+ *
+ * Returns          Pointer to the name or NULL
+ *
+ ******************************************************************************/
+char* BTM_SecReadDevName(const RawAddress& bd_addr);
+
+/*****************************************************************************
+ *  POWER MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTM_PmRegister
+ *
+ * Description      register or deregister with power manager
+ *
+ * Returns          BTM_SUCCESS if successful,
+ *                  BTM_NO_RESOURCES if no room to hold registration
+ *                  BTM_ILLEGAL_VALUE
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
+                           tBTM_PM_STATUS_CBACK* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetPowerMode
+ *
+ * Description      store the mode in control block or
+ *                  alter ACL connection behavior.
+ *
+ * Returns          BTM_SUCCESS if successful,
+ *                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
+                             const tBTM_PM_PWR_MD* p_mode);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadPowerMode
+ *
+ * Description      This returns the current mode for a specific
+ *                  ACL connection.
+ *
+ * Input Param      remote_bda - device address of desired ACL connection
+ *
+ * Output Param     p_mode - address where the current mode is copied into.
+ *                          BTM_ACL_MODE_NORMAL
+ *                          BTM_ACL_MODE_HOLD
+ *                          BTM_ACL_MODE_SNIFF
+ *                          BTM_ACL_MODE_PARK
+ *                          (valid only if return code is BTM_SUCCESS)
+ *
+ * Returns          BTM_SUCCESS if successful,
+ *                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadPowerMode(const RawAddress& remote_bda,
+                              tBTM_PM_MODE* p_mode);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetSsrParams
+ *
+ * Description      This sends the given SSR parameters for the given ACL
+ *                  connection if it is in ACTIVE mode.
+ *
+ * Input Param      remote_bda - device address of desired ACL connection
+ *                  max_lat    - maximum latency (in 0.625ms)(0-0xFFFE)
+ *                  min_rmt_to - minimum remote timeout
+ *                  min_loc_to - minimum local timeout
+ *
+ *
+ * Returns          BTM_SUCCESS if the HCI command is issued successful,
+ *                  BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *                  BTM_CMD_STORED if the command is stored
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat,
+                             uint16_t min_rmt_to, uint16_t min_loc_to);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetHCIConnHandle
+ *
+ * Description      This function is called to get the handle for an ACL
+ *                  connection to a specific remote BD Address.
+ *
+ * Returns          the handle of the connection, or 0xFFFF if none.
+ *
+ ******************************************************************************/
+uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda,
+                              tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTM_DeleteStoredLinkKey
+ *
+ * Description      This function is called to delete link key for the specified
+ *                  device addresses from the NVRAM storage attached to the
+ *                  Bluetooth controller.
+ *
+ * Parameters:      bd_addr      - Addresses of the devices
+ *                  p_cb         - Call back function to be called to return
+ *                                 the results
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr,
+                                    tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_WriteEIR
+ *
+ * Description      This function is called to write EIR data to controller.
+ *
+ * Parameters       p_buff - allocated HCI command buffer including extended
+ *                           inquriry response
+ *
+ * Returns          BTM_SUCCESS  - if successful
+ *                  BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff);
+
+/*******************************************************************************
+ *
+ * Function         BTM_HasEirService
+ *
+ * Description      This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters       p_eir_uuid - bit map of UUID list
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          true - if found
+ *                  false - if not found
+ *
+ ******************************************************************************/
+bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function         BTM_HasInquiryEirService
+ *
+ * Description      Return if a UUID is in the bit map of a UUID list.
+ *
+ * Parameters       p_results - inquiry results
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          BTM_EIR_FOUND - if found
+ *                  BTM_EIR_NOT_FOUND - if not found and it is a complete list
+ *                  BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results,
+                                                uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function         BTM_AddEirService
+ *
+ * Description      This function is called to add a service in the bit map UUID
+ *                  list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function         BTM_RemoveEirService
+ *
+ * Description      This function is called to remove a service from the bit map
+ *                  UUID list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  uuid16 - UUID 16-bit
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetEirSupportedServices
+ *
+ * Description      This function is called to get UUID list from bit map UUID
+ *                  list.
+ *
+ * Parameters       p_eir_uuid - bit mask of UUID list for EIR
+ *                  p - reference of current pointer of EIR
+ *                  max_num_uuid16 - max number of UUID can be written in EIR
+ *                  num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns          BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ *                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
+                                    uint8_t max_num_uuid16,
+                                    uint8_t* p_num_uuid16);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetEirUuidList
+ *
+ * Description      This function parses EIR and returns UUID list.
+ *
+ * Parameters       p_eir - EIR
+ *                  eirl_len - EIR len
+ *                  uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ *                              Uuid::kNumBytes128
+ *                  p_num_uuid - return number of UUID in found list
+ *                  p_uuid_list - return UUID 16-bit list
+ *                  max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns          0 - if not found
+ *                  BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_16BITS_UUID_TYPE
+ *                  BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_32BITS_UUID_TYPE
+ *                  BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ *                  BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len, uint8_t uuid_size,
+                           uint8_t* p_num_uuid, uint8_t* p_uuid_list,
+                           uint8_t max_num_uuid);
+
+/*****************************************************************************
+ *  SCO OVER HCI
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function         BTM_ConfigScoPath
+ *
+ * Description      This function enable/disable SCO over HCI and registers SCO
+ *                  data callback if SCO over HCI is enabled.
+ *
+ * Parameter        path: SCO or HCI
+ *                  p_sco_data_cb: callback function or SCO data if path is set
+ *                                 to transport.
+ *                  p_pcm_param: pointer to the PCM interface parameter. If a
+ *                               NULL pointer is used, the PCM parameter
+ *                               maintained in the control block will be used;
+ *                               otherwise update the control block value.
+ *                  err_data_rpt: Lisbon feature to enable the erronous data
+ *                                report or not.
+ *
+ * Returns          BTM_SUCCESS if the successful.
+ *                  BTM_NO_RESOURCES: no rsource to start the command.
+ *                  BTM_ILLEGAL_VALUE: invalid callback function pointer.
+ *                  BTM_CMD_STARTED : Command sent. Waiting for command
+ *                                    complete event.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ConfigScoPath(esco_data_path_t path,
+                              tBTM_SCO_DATA_CB* p_sco_data_cb,
+                              tBTM_SCO_PCM_PARAM* p_pcm_param,
+                              bool err_data_rpt);
+
+/*******************************************************************************
+ *
+ * Function         BTM_WriteScoData
+ *
+ * Description      This function write SCO data to a specified instance. The
+ *                  data to be written p_buf needs to carry an offset of
+ *                  HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+ *                  exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is
+ *                  set to 60 and is configurable. Data longer than the maximum
+ *                  bytes will be truncated.
+ *
+ * Returns          BTM_SUCCESS: data write is successful
+ *                  BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+ *                  BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO
+ *                                      packet size.
+ *                  BTM_NO_RESOURCES: no resources.
+ *                  BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is
+ *                                    not routed via HCI.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_WriteScoData(uint16_t sco_inx, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetARCMode
+ *
+ * Description      Send Audio Routing Control command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_SetARCMode(uint8_t iface, uint8_t arc_mode,
+                    tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_PCM2Setup_Write
+ *
+ * Description      Send PCM2_Setup write command.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_PCM2Setup_Write(bool clk_master, tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_PM_ReadControllerState
+ *
+ * Description      This function is called to obtain the controller state
+ *
+ * Returns          Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and
+ *                                    BTM_CONTRL_IDLE)
+ *
+ ******************************************************************************/
+tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void);
+
+/**
+ *
+ * BLE API
+ */
+/*******************************************************************************
+ *
+ * Function         BTM_SecAddBleDevice
+ *
+ * Description      Add/modify device.  This function will be normally called
+ *                  during host startup to restore all required information
+ *                  for a LE device stored in the NVRAM.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  bd_name          - Name of the peer device. NULL if unknown.
+ *                  dev_type         - Remote device's device type.
+ *                  addr_type        - LE device address type.
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleDevice(const RawAddress& bd_addr, BD_NAME bd_name,
+                         tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecAddBleKey
+ *
+ * Description      Add/modify LE device information.  This function will be
+ *                  normally called during host startup to restore all required
+ *                  information stored in the NVRAM.
+ *
+ * Parameters:      bd_addr          - BD address of the peer
+ *                  p_le_key         - LE key values.
+ *                  key_type         - LE SMP key type.
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
+                      tBTM_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleObtainVendorCapabilities
+ *
+ * Description      This function is called to obatin vendor capabilties
+ *
+ * Parameters       p_cmn_vsc_cb - Returns the vednor capabilities
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleObtainVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+
+/**
+ * This function is called to set scan parameters. |cb| is called with operation
+ * status
+ **/
+void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window,
+                          tBLE_SCAN_MODE scan_type,
+                          base::Callback<void(uint8_t)> cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleGetVendorCapabilities
+ *
+ * Description      This function reads local LE features
+ *
+ * Parameters       p_cmn_vsc_cb : Locala LE capability structure
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetStorageConfig
+ *
+ * Description      This function is called to setup storage configuration and
+ *                  setup callbacks.
+ *
+ * Parameters       uint8_t batch_scan_full_max -Batch scan full maximum
+                    uint8_t batch_scan_trunc_max - Batch scan truncated value
+ maximum
+                    uint8_t batch_scan_notify_threshold - Threshold value
+                    cb - Setup callback
+                    tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback -Threshold
+ callback
+                    void *p_ref - Reference value
+ *
+ *
+ ******************************************************************************/
+void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max,
+                             uint8_t batch_scan_trunc_max,
+                             uint8_t batch_scan_notify_threshold,
+                             base::Callback<void(uint8_t /* status */)> cb,
+                             tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback,
+                             tBTM_BLE_REF_VALUE ref_value);
+
+/* This function is called to enable batch scan */
+void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+                            uint32_t scan_interval, uint32_t scan_window,
+                            tBTM_BLE_DISCARD_RULE discard_rule,
+                            tBLE_ADDR_TYPE addr_type,
+                            base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to disable batch scanning */
+void BTM_BleDisableBatchScan(base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to read batch scan reports */
+void BTM_BleReadScanReports(tBLE_SCAN_MODE scan_mode,
+                            tBTM_BLE_SCAN_REP_CBACK cb);
+
+/* This function is called to setup the callback for tracking */
+void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback,
+                            tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleWriteScanRsp
+ *
+ * Description      This function is called to write LE scan response.
+ *
+ * Parameters:      p_scan_rsp: scan response.
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+void BTM_BleWriteScanRsp(uint8_t* data, uint8_t length,
+                         tBTM_BLE_ADV_DATA_CMPL_CBACK* p_adv_data_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleObserve
+ *
+ * Description      This procedure keep the device listening for advertising
+ *                  events from a broadcast device.
+ *
+ * Parameters       start: start or stop observe.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
+                           tBTM_INQ_RESULTS_CB* p_results_cb,
+                           tBTM_CMPL_CB* p_cmpl_cb);
+
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot();
+
+/** Returns local device identity root (IR) */
+const Octet16& BTM_GetDeviceIDRoot();
+
+/** Return local device DHK. */
+const Octet16& BTM_GetDeviceDHK();
+
+/*******************************************************************************
+ *
+ * Function         BTM_SecurityGrant
+ *
+ * Description      This function is called to grant security process.
+ *
+ * Parameters       bd_addr - peer device bd address.
+ *                  res     - result of the operation BTM_SUCCESS if success.
+ *                            Otherwise, BTM_REPEATED_ATTEMPTS is too many
+ *                            attempts.
+ *
+ * Returns          None
+ *
+ ******************************************************************************/
+void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BlePasskeyReply
+ *
+ * Description      This function is called after Security Manager submitted
+ *                  passkey request to the application.
+ *
+ * Parameters:      bd_addr - Address of the device for which passkey was
+ *                            requested
+ *                  res     - result of the operation SMP_SUCCESS if success
+ *                  passkey - numeric value in the range of
+ *                               BTM_MIN_PASSKEY_VAL(0) -
+ *                               BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
+                         uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleConfirmReply
+ *
+ * Description      This function is called after Security Manager submitted
+ *                  numeric comparison request to the application.
+ *
+ * Parameters:      bd_addr      - Address of the device with which numeric
+ *                                 comparison was requested
+ *                  res          - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function         BTM_LeOobDataReply
+ *
+ * Description      This function is called to provide the OOB data for
+ *                  SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters:      bd_addr     - Address of the peer device
+ *                  res         - result of the operation SMP_SUCCESS if success
+ *                  p_data      - simple pairing Randomizer  C.
+ *
+ ******************************************************************************/
+void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
+                         uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSecureConnectionOobDataReply
+ *
+ * Description      This function is called to provide the OOB data for
+ *                  SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ *                  data is available
+ *
+ * Parameters:      bd_addr     - Address of the peer device
+ *                  p_c         - pointer to Confirmation
+ *                  p_r         - pointer to Randomizer.
+ *
+ ******************************************************************************/
+void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
+                                         uint8_t* p_c, uint8_t* p_r);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleDataSignature
+ *
+ * Description      This function is called to sign the data using AES128 CMAC
+ *                  algorith.
+ *
+ * Parameter        bd_addr: target device the data to be signed for.
+ *                  p_text: singing data
+ *                  len: length of the signing data
+ *                  signature: output parameter where data signature is going to
+ *                             be stored.
+ *
+ * Returns          true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
+                          uint16_t len, BLE_SIGNATURE signature);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleVerifySignature
+ *
+ * Description      This function is called to verify the data signature
+ *
+ * Parameter        bd_addr: target device the data to be signed for.
+ *                  p_orig:  original data before signature.
+ *                  len: length of the signing data
+ *                  counter: counter used when doing data signing
+ *                  p_comp: signature to be compared against.
+
+ * Returns          true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
+                            uint16_t len, uint32_t counter, uint8_t* p_comp);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectionAddr
+ *
+ * Description      Read the local device random address.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
+                            RawAddress& local_conn_addr,
+                            tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_IsBleConnection
+ *
+ * Description      This function is called to check if the connection handle
+ *                  for an LE link
+ *
+ * Returns          true if connection is LE link, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_IsBleConnection(uint16_t conn_handle);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadRemoteConnectionAddr
+ *
+ * Description      Read the remote device address currently used.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
+                                  RawAddress& conn_addr,
+                                  tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleLoadLocalKeys
+ *
+ * Description      Local local identity key, encryption root or sign counter.
+ *
+ * Parameters:      key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ *                            BTM_BLE_KEY_TYPE_ER
+ *                            or BTM_BLE_KEY_TYPE_COUNTER.
+ *                  p_key: pointer to the key.
+ *
+ * Returns          non2.
+ *
+ ******************************************************************************/
+void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key);
+
+/********************************************************
+ *
+ * Function         BTM_BleSetPrefConnParams
+ *
+ * Description      Set a peripheral's preferred connection parameters. When
+ *                  any of the value does not want to be updated while others
+ *                  do, use BTM_BLE_CONN_PARAM_UNDEF for the ones want to
+ *                  leave untouched.
+ *
+ * Parameters:      bd_addr          - BD address of the peripheral
+ *                  min_conn_int     - minimum preferred connection interval
+ *                  max_conn_int     - maximum preferred connection interval
+ *                  slave_latency    - preferred slave latency
+ *                  supervision_tout - preferred supervision timeout
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
+                              uint16_t max_conn_int, uint16_t slave_latency,
+                              uint16_t supervision_tout);
+
+/******************************************************************************
+ *
+ * Function         BTM_BleSetConnScanParams
+ *
+ * Description      Set scan parameters used in BLE connection request
+ *
+ * Parameters:      scan_interval    - scan interval
+ *                  scan_window      - scan window
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window);
+
+/******************************************************************************
+ *
+ * Function         BTM_BleReadControllerFeatures
+ *
+ * Description      Reads BLE specific controller features
+ *
+ * Parameters:      tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when
+ *                  features are read
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM__BLEReadDiscoverability
+ *
+ * Description      This function is called to read the current LE
+ *                  discoverability mode of the device.
+ *
+ * Returns          BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or
+ *                     BTM_BLE_GENRAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadDiscoverability();
+
+/*******************************************************************************
+ *
+ * Function         BTM__BLEReadConnectability
+ *
+ * Description      This function is called to read the current LE
+ *                  connectibility mode of the device.
+ *
+ * Returns          BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadConnectability();
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadDevInfo
+ *
+ * Description      This function is called to read the device/address type
+ *                  of BD address.
+ *
+ * Parameter        remote_bda: remote device address
+ *                  p_dev_type: output parameter to read the device type.
+ *                  p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type,
+                     tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function         BTM_ReadConnectedTransportAddress
+ *
+ * Description      This function is called to read the paired device/address
+ *                  type of other device paired corresponding to the BD_address
+ *
+ * Parameter        remote_bda: remote device address, carry out the transport
+ *                              address
+ *                  transport: active transport
+ *
+ * Return           true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
+                                       tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleConfigPrivacy
+ *
+ * Description      This function is called to enable or disable the privacy in
+ *                  the local device.
+ *
+ * Parameters       enable: true to enable it; false to disable it.
+ *
+ * Returns          bool    privacy mode set success; otherwise failed.
+ *
+ ******************************************************************************/
+bool BTM_BleConfigPrivacy(bool enable);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleLocalPrivacyEnabled
+ *
+ * Description        Checks if local device supports private address
+ *
+ * Returns          Return true if local privacy is enabled else false
+ *
+ ******************************************************************************/
+bool BTM_BleLocalPrivacyEnabled(void);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleEnableMixedPrivacyMode
+ *
+ * Description      This function is called to enabled Mixed mode if privacy 1.2
+ *                  is applicable in controller.
+ *
+ * Parameters       mixed_on:  mixed mode to be used or not.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleEnableMixedPrivacyMode(bool mixed_on);
+
+/*******************************************************************************
+ *
+ * Function          BTM_BleMaxMultiAdvInstanceCount
+ *
+ * Description      Returns the maximum number of multi adv instances supported
+ *                  by the controller.
+ *
+ * Returns          Max multi adv instance count
+ *
+ ******************************************************************************/
+uint8_t BTM_BleMaxMultiAdvInstanceCount();
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetConnectableMode
+ *
+ * Description      This function is called to set BLE connectable mode for a
+ *                  peripheral device.
+ *
+ * Parameters       connectable_mode:  directed connectable mode, or
+ *                                     non-directed. It can be
+ *                                     BTM_BLE_CONNECT_EVT,
+ *                                     BTM_BLE_CONNECT_DIR_EVT or
+ *                                     BTM_BLE_CONNECT_LO_DUTY_DIR_EVT
+ *
+ * Returns          BTM_ILLEGAL_VALUE if controller does not support BLE.
+ *                  BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleTurnOnPrivacyOnRemote
+ *
+ * Description      This function is called to enable or disable the privacy on
+ *                  the remote device.
+ *
+ * Parameters       bd_addr: remote device address.
+ *                  privacy_on: true to enable it; false to disable it.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void BTM_BleTurnOnPrivacyOnRemote(const RawAddress& bd_addr, bool privacy_on);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleUpdateAdvFilterPolicy
+ *
+ * Description      This function update the filter policy of advertiser.
+ *
+ * Parameter        adv_policy: advertising filter policy
+ *
+ * Return           void
+ ******************************************************************************/
+void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleReceiverTest
+ *
+ * Description      This function is called to start the LE Receiver test
+ *
+ * Parameter       rx_freq - Frequency Range
+ *               p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleTransmitterTest
+ *
+ * Description      This function is called to start the LE Transmitter test
+ *
+ * Parameter       tx_freq - Frequency Range
+ *                       test_data_len - Length in bytes of payload data in each
+ *                                       packet
+ *                       packet_payload - Pattern to use in the payload
+ *                       p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
+                            uint8_t packet_payload,
+                            tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleTestEnd
+ *
+ * Description     This function is called to stop the in-progress TX or RX test
+ *
+ * Parameter       p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_UseLeLink
+ *
+ * Description      Select the underlying physical link to use.
+ *
+ * Returns          true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+bool BTM_UseLeLink(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleStackEnable
+ *
+ * Description      Enable/Disable BLE functionality on stack regardless of
+ *                  controller capability.
+ *
+ * Parameters:      enable: true to enable, false to disable.
+ *
+ * Returns          true if added OK, else false
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleStackEnable(bool enable);
+
+/*******************************************************************************
+ *
+ * Function         BTM_GetLeSecurityState
+ *
+ * Description      This function is called to get security mode 1 flags and
+ *                  encryption key size for LE peer.
+ *
+ * Returns          bool    true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+bool BTM_GetLeSecurityState(const RawAddress& bd_addr,
+                            uint8_t* p_le_dev_sec_flags,
+                            uint8_t* p_le_key_size);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSecurityProcedureIsRunning
+ *
+ * Description      This function indicates if LE security procedure is
+ *                  currently running with the peer.
+ *
+ * Returns          bool true if security procedure is running, false otherwise.
+ *
+ ******************************************************************************/
+bool BTM_BleSecurityProcedureIsRunning(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleGetSupportedKeySize
+ *
+ * Description      This function gets the maximum encryption key size in bytes
+ *                  the local device can suport.
+ *                  record.
+ *
+ * Returns          the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleAdvFilterParamSetup
+ *
+ * Description      This function is called to setup the adv data payload filter
+ *                  condition.
+ *
+ ******************************************************************************/
+void BTM_BleAdvFilterParamSetup(
+    int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+    std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+    tBTM_BLE_PF_PARAM_CB cb);
+
+/**
+ * This functions are called to configure the adv data payload filter condition
+ */
+void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+                   std::vector<ApcfCommand> commands, tBTM_BLE_PF_CFG_CBACK cb);
+void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+                     tBTM_BLE_PF_CFG_CBACK cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleEnableDisableFilterFeature
+ *
+ * Description      Enable or disable the APCF feature
+ *
+ * Parameters       enable - true - enables APCF, false - disables APCF
+ *
+ ******************************************************************************/
+void BTM_BleEnableDisableFilterFeature(uint8_t enable,
+                                       tBTM_BLE_PF_STATUS_CBACK p_stat_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleGetEnergyInfo
+ *
+ * Description      This function obtains the energy info
+ *
+ * Parameters       p_ener_cback - Callback pointer
+ *
+ * Returns          status
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback);
+
+/*******************************************************************************
+ *
+ * Function         BTM_SetBleDataLength
+ *
+ * Description      Set the maximum BLE transmission packet size
+ *
+ * Returns          BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
+                                 uint16_t tx_pdu_length);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleReadPhy
+ *
+ * Description      To read the current PHYs for specified LE connection
+ *
+ *
+ * Returns          BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+void BTM_BleReadPhy(
+    const RawAddress& bd_addr,
+    base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetDefaultPhy
+ *
+ * Description      To set preferred PHY for ensuing LE connections
+ *
+ *
+ * Returns          BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetDefaultPhy(uint8_t all_phys, uint8_t tx_phys,
+                                 uint8_t rx_phys);
+
+/*******************************************************************************
+ *
+ * Function         BTM_BleSetPhy
+ *
+ * Description      To set PHY preferences for specified LE connection
+ *
+ *
+ * Returns          BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
+                   uint16_t phy_options);
+
+void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+                          tBTM_BLE_PF_FILT_INDEX filt_index,
+                          std::vector<uint8_t> name, tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+                         tBTM_BLE_PF_FILT_INDEX filt_index);
+
+void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action,
+                         tBTM_BLE_PF_FILT_INDEX filt_index, uint16_t company_id,
+                         uint16_t company_id_mask, std::vector<uint8_t> data,
+                         std::vector<uint8_t> data_mask,
+                         tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action,
+                                 tBTM_BLE_PF_FILT_INDEX filt_index,
+                                 std::vector<uint8_t> data,
+                                 std::vector<uint8_t> data_mask,
+                                 tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+                           tBTM_BLE_PF_FILT_INDEX filt_index, tBLE_BD_ADDR addr,
+                           tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+                           tBTM_BLE_PF_FILT_INDEX filt_index,
+                           tBTM_BLE_PF_COND_TYPE filter_type,
+                           const bluetooth::Uuid& uuid,
+                           tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+                           const bluetooth::Uuid& uuid_mask,
+                           tBTM_BLE_PF_CFG_CBACK cb);
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/controller.cc b/main/shim/controller.cc
new file mode 100644
index 0000000..284d360
--- /dev/null
+++ b/main/shim/controller.cc
@@ -0,0 +1,341 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_shim_controller"
+
+#include "main/shim/controller.h"
+#include "btcore/include/module.h"
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+
+using ::bluetooth::shim::GetController;
+
+constexpr uint8_t kPageZero = 0;
+constexpr uint8_t kPageOne = 1;
+constexpr uint8_t kPageTwo = 2;
+constexpr uint8_t kMaxFeaturePage = 3;
+
+constexpr int kMaxSupportedCodecs = 8;  // MAX_LOCAL_SUPPORTED_CODECS_SIZE
+
+constexpr uint8_t kPhyLe1M = 0x01;
+
+/**
+ * Interesting commands supported by controller
+ */
+constexpr int kReadRemoteExtendedFeatures = 0x41c;
+constexpr int kEnhancedSetupSynchronousConnection = 0x428;
+constexpr int kEnhancedAcceptSynchronousConnection = 0x429;
+constexpr int kLeSetPrivacyMode = 0x204e;
+
+constexpr int kHciDataPreambleSize = 4;  // #define HCI_DATA_PREAMBLE_SIZE 4
+
+// Module lifecycle functions
+static future_t* start_up(void);
+static future_t* shut_down(void);
+
+EXPORT_SYMBOL extern const module_t gd_controller_module = {
+    .name = GD_CONTROLLER_MODULE,
+    .init = nullptr,
+    .start_up = start_up,
+    .shut_down = shut_down,
+    .clean_up = nullptr,
+    .dependencies = {GD_SHIM_MODULE, nullptr}};
+
+struct {
+  bool ready;
+  uint64_t feature[kMaxFeaturePage];
+  uint64_t le_feature[kMaxFeaturePage];
+  RawAddress raw_address;
+  bt_version_t bt_version;
+  uint8_t local_supported_codecs[kMaxSupportedCodecs];
+  uint8_t number_of_local_supported_codecs;
+  uint64_t le_supported_states;
+  uint8_t phy;
+} data_;
+
+static future_t* start_up(void) {
+  LOG_INFO(LOG_TAG, "%s Starting up", __func__);
+  data_.ready = true;
+
+  std::string string_address = GetController()->GetControllerMacAddress();
+  RawAddress::FromString(string_address, data_.raw_address);
+
+  data_.le_supported_states =
+      bluetooth::shim::GetController()->GetControllerLeSupportedStates();
+
+  LOG_INFO(LOG_TAG, "Mac address:%s", string_address.c_str());
+
+  data_.phy = kPhyLe1M;
+
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+  data_.ready = false;
+  return future_new_immediate(FUTURE_SUCCESS);
+}
+
+/**
+ * Module methods
+ */
+#define BIT(x) (0x1ULL << (x))
+
+static bool get_is_ready(void) { return data_.ready; }
+
+static const RawAddress* get_address(void) { return &data_.raw_address; }
+
+static const bt_version_t* get_bt_version(void) { return &data_.bt_version; }
+
+static const bt_device_features_t* get_features_classic(int index) {
+  CHECK(index >= 0 && index < kMaxFeaturePage);
+  data_.feature[index] =
+      bluetooth::shim::GetController()->GetControllerLocalExtendedFeatures(
+          index);
+  return (const bt_device_features_t*)&data_.feature[index];
+}
+
+static uint8_t get_last_features_classic_index(void) {
+  return bluetooth::shim::GetController()
+      ->GetControllerLocalExtendedFeaturesMaxPageNumber();
+}
+
+static uint8_t* get_local_supported_codecs(uint8_t* number_of_codecs) {
+  CHECK(number_of_codecs != nullptr);
+  if (data_.number_of_local_supported_codecs != 0) {
+    *number_of_codecs = data_.number_of_local_supported_codecs;
+    return data_.local_supported_codecs;
+  }
+  return (uint8_t*)nullptr;
+}
+
+static const bt_device_features_t* get_features_ble(void) {
+  return (const bt_device_features_t*)&data_.le_feature[0];
+}
+
+static const uint8_t* get_ble_supported_states(void) {
+  return (const uint8_t*)&data_.le_supported_states;
+}
+
+static bool supports_simple_pairing(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageOne) &
+         BIT(51);
+}
+
+static bool supports_secure_connections(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageTwo) & BIT(8);
+}
+
+static bool supports_simultaneous_le_bredr(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+         BIT(49);
+}
+
+static bool supports_reading_remote_extended_features(void) {
+  return GetController()->IsCommandSupported(kReadRemoteExtendedFeatures);
+}
+
+static bool supports_interlaced_inquiry_scan(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+         BIT(28);
+}
+
+static bool supports_rssi_with_inquiry_results(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+         BIT(28);
+}
+
+static bool supports_extended_inquiry_response(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+         BIT(48);
+}
+
+static bool supports_master_slave_role_switch(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+         BIT(5);
+}
+
+static bool supports_enhanced_setup_synchronous_connection(void) {
+  return GetController()->IsCommandSupported(
+      kEnhancedSetupSynchronousConnection);
+}
+
+static bool supports_enhanced_accept_synchronous_connection(void) {
+  return GetController()->IsCommandSupported(
+      kEnhancedAcceptSynchronousConnection);
+}
+
+static bool supports_ble(void) {
+  return GetController()->GetControllerLocalExtendedFeatures(kPageOne) & BIT(1);
+}
+
+static bool supports_ble_privacy(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(6);
+}
+
+static bool supports_ble_set_privacy_mode() {
+  return GetController()->IsCommandSupported(kLeSetPrivacyMode);
+}
+
+static bool supports_ble_packet_extension(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(5);
+}
+
+static bool supports_ble_connection_parameters_request(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(2);
+}
+
+static bool supports_ble_2m_phy(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(8);
+}
+
+static bool supports_ble_coded_phy(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(11);
+}
+
+static bool supports_ble_extended_advertising(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(12);
+}
+
+static bool supports_ble_periodic_advertising(void) {
+  return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(13);
+}
+
+static uint16_t get_acl_data_size_classic(void) {
+  return GetController()->GetControllerAclPacketLength();
+}
+
+static uint16_t get_acl_data_size_ble(void) {
+  ::bluetooth::shim::LeBufferSize le_buffer_size =
+      GetController()->GetControllerLeBufferSize();
+  return le_buffer_size.le_data_packet_length;
+}
+
+static uint16_t get_acl_packet_size_classic(void) {
+  return get_acl_data_size_classic() + kHciDataPreambleSize;
+}
+
+static uint16_t get_acl_packet_size_ble(void) {
+  return get_acl_data_size_ble() + kHciDataPreambleSize;
+}
+
+static uint16_t get_ble_suggested_default_data_length(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static uint16_t get_ble_maximum_tx_data_length(void) {
+  ::bluetooth::shim::LeMaximumDataLength le_maximum_data_length =
+      GetController()->GetControllerLeMaximumDataLength();
+  return le_maximum_data_length.supported_max_tx_octets;
+}
+
+static uint16_t get_ble_maxium_advertising_data_length(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static uint8_t get_ble_number_of_supported_advertising_sets(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static uint16_t get_acl_buffer_count_classic(void) {
+  return GetController()->GetControllerNumAclPacketBuffers();
+}
+
+static uint8_t get_acl_buffer_count_ble(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static uint8_t get_ble_white_list_size(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static uint8_t get_ble_resolving_list_max_size(void) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+  return 0;
+}
+
+static void set_ble_resolving_list_max_size(int resolving_list_max_size) {
+  LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+}
+
+static uint8_t get_le_all_initiating_phys() { return data_.phy; }
+
+static const controller_t interface = {
+    get_is_ready,
+
+    get_address,
+    get_bt_version,
+
+    get_features_classic,
+    get_last_features_classic_index,
+
+    get_features_ble,
+    get_ble_supported_states,
+
+    supports_simple_pairing,
+    supports_secure_connections,
+    supports_simultaneous_le_bredr,
+    supports_reading_remote_extended_features,
+    supports_interlaced_inquiry_scan,
+    supports_rssi_with_inquiry_results,
+    supports_extended_inquiry_response,
+    supports_master_slave_role_switch,
+    supports_enhanced_setup_synchronous_connection,
+    supports_enhanced_accept_synchronous_connection,
+
+    supports_ble,
+    supports_ble_packet_extension,
+    supports_ble_connection_parameters_request,
+    supports_ble_privacy,
+    supports_ble_set_privacy_mode,
+    supports_ble_2m_phy,
+    supports_ble_coded_phy,
+    supports_ble_extended_advertising,
+    supports_ble_periodic_advertising,
+
+    get_acl_data_size_classic,
+    get_acl_data_size_ble,
+
+    get_acl_packet_size_classic,
+    get_acl_packet_size_ble,
+    get_ble_suggested_default_data_length,
+    get_ble_maximum_tx_data_length,
+    get_ble_maxium_advertising_data_length,
+    get_ble_number_of_supported_advertising_sets,
+
+    get_acl_buffer_count_classic,
+    get_acl_buffer_count_ble,
+
+    get_ble_white_list_size,
+
+    get_ble_resolving_list_max_size,
+    set_ble_resolving_list_max_size,
+    get_local_supported_codecs,
+    get_le_all_initiating_phys};
+
+const controller_t* bluetooth::shim::controller_get_interface() {
+  static bool loaded = false;
+  if (!loaded) {
+    loaded = true;
+  }
+  return &interface;
+}
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/main/shim/controller.h
similarity index 75%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to main/shim/controller.h
index 8a08509..6b77982 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/main/shim/controller.h
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#pragma once
+
+#include "device/include/controller.h"
+
+static const char GD_CONTROLLER_MODULE[] = "gd_controller_module";
 
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+const controller_t* controller_get_interface();
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/entry.cc b/main/shim/entry.cc
new file mode 100644
index 0000000..4655219
--- /dev/null
+++ b/main/shim/entry.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 "main/shim/entry.h"
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "osi/include/future.h"
+
+using bluetooth::shim::GetGabeldorscheStack;
+
+future_t* bluetooth::shim::StartGabeldorscheStack() {
+  GetGabeldorscheStack()->Start();
+  return (future_t*)nullptr;
+}
+
+future_t* bluetooth::shim::StopGabeldorscheStack() {
+  GetGabeldorscheStack()->Stop();
+  return (future_t*)nullptr;
+}
+
+bluetooth::shim::IController* bluetooth::shim::GetController() {
+  return GetGabeldorscheStack()->GetController();
+}
+
+bluetooth::shim::IConnectability* bluetooth::shim::GetConnectability() {
+  return GetGabeldorscheStack()->GetConnectability();
+}
+
+bluetooth::shim::IDiscoverability* bluetooth::shim::GetDiscoverability() {
+  return GetGabeldorscheStack()->GetDiscoverability();
+}
+
+bluetooth::shim::IInquiry* bluetooth::shim::GetInquiry() {
+  return GetGabeldorscheStack()->GetInquiry();
+}
+
+bluetooth::shim::IHciLayer* bluetooth::shim::GetHciLayer() {
+  return GetGabeldorscheStack()->GetHciLayer();
+}
+
+bluetooth::shim::IL2cap* bluetooth::shim::GetL2cap() {
+  return GetGabeldorscheStack()->GetL2cap();
+}
+
+bluetooth::shim::IName* bluetooth::shim::GetName() {
+  return GetGabeldorscheStack()->GetName();
+}
+
+bluetooth::shim::IPage* bluetooth::shim::GetPage() {
+  return GetGabeldorscheStack()->GetPage();
+}
diff --git a/main/shim/entry.h b/main/shim/entry.h
new file mode 100644
index 0000000..2ffd2e5
--- /dev/null
+++ b/main/shim/entry.h
@@ -0,0 +1,51 @@
+/*
+ * 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
+
+/**
+ * Entrypoints called into Gabeldorsche from legacy stack
+ *
+ * Any marshalling/unmarshalling, data transformation of APIs to
+ * or from the Gabeldorsche stack may be placed here.
+ *
+ * The idea is to effectively provide a binary interface to prevent cross
+ * contamination of data structures and the like between the stacks.
+ *
+ * **ABSOLUTELY** No reference to Gabeldorsche stack other than well defined
+ * interfaces may be made here
+ */
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "osi/include/future.h"
+
+namespace bluetooth {
+namespace shim {
+
+future_t* StartGabeldorscheStack();
+future_t* StopGabeldorscheStack();
+
+bluetooth::shim::IController* GetController();
+bluetooth::shim::IDiscoverability* GetDiscoverability();
+bluetooth::shim::IConnectability* GetConnectability();
+bluetooth::shim::IInquiry* GetInquiry();
+bluetooth::shim::IHciLayer* GetHciLayer();
+bluetooth::shim::IL2cap* GetL2cap();
+bluetooth::shim::IName* GetName();
+bluetooth::shim::IPage* GetPage();
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/main/shim/entry_for_test.cc
similarity index 64%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to main/shim/entry_for_test.cc
index 8a08509..26b9b22 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/main/shim/entry_for_test.cc
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
 
-namespace bluetooth {
-namespace l2cap {
-
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
-
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+/**
+ * Entrypoints for stubbed bluetooth test library
+ *
+ * Gd stack is not supported using legacy test modes
+ */
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+  return (bluetooth::shim::IStack*)nullptr;
+}
diff --git a/main/shim/hci_layer.cc b/main/shim/hci_layer.cc
new file mode 100644
index 0000000..ba21cae
--- /dev/null
+++ b/main/shim/hci_layer.cc
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_shim_hci"
+
+#include <base/bind.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
+#include <algorithm>
+#include <cstdint>
+
+#include "btcore/include/module.h"
+#include "main/shim/hci_layer.h"
+#include "main/shim/shim.h"
+#include "osi/include/allocator.h"
+#include "osi/include/future.h"
+#include "stack/include/bt_types.h"
+
+/**
+ * Callback data wrapped as opaque token bundled with the command
+ * transmit request to the Gd layer.
+ *
+ * Upon completion a token for a corresponding command transmit.
+ * request is returned from the Gd layer.
+ */
+using CommandCallbackData = struct {
+  void* context;
+  command_complete_cb complete_callback;
+  command_status_cb status_callback;
+};
+
+constexpr size_t kBtHdrSize = sizeof(BT_HDR);
+constexpr size_t kCommandLengthSize = sizeof(uint8_t);
+constexpr size_t kCommandOpcodeSize = sizeof(uint16_t);
+
+static hci_t interface;
+static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards;
+
+static future_t* hci_module_shut_down(void);
+static future_t* hci_module_start_up(void);
+
+static void OnCommandComplete(uint16_t command_op_code,
+                              std::vector<const uint8_t> data,
+                              const void* token) {
+  BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+  std::copy(data.begin(), data.end(), response->data);
+  response->len = data.size();
+
+  const CommandCallbackData* command_callback_data =
+      static_cast<const CommandCallbackData*>(token);
+  CHECK(command_callback_data->complete_callback != nullptr);
+
+  command_callback_data->complete_callback(response,
+                                           command_callback_data->context);
+  delete command_callback_data;
+}
+
+static void OnCommandStatus(uint16_t command_op_code,
+                            std::vector<const uint8_t> data, const void* token,
+                            uint8_t status) {
+  BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+  std::copy(data.begin(), data.end(), response->data);
+  response->len = data.size();
+
+  const CommandCallbackData* command_callback_data =
+      static_cast<const CommandCallbackData*>(token);
+  CHECK(command_callback_data->status_callback != nullptr);
+
+  command_callback_data->status_callback(status, response,
+                                         command_callback_data->context);
+  delete command_callback_data;
+}
+
+EXPORT_SYMBOL extern const module_t gd_hci_module = {
+    .name = GD_HCI_MODULE,
+    .init = nullptr,
+    .start_up = hci_module_start_up,
+    .shut_down = hci_module_shut_down,
+    .clean_up = nullptr,
+    .dependencies = {GD_SHIM_MODULE, nullptr}};
+
+static future_t* hci_module_start_up(void) {
+  bluetooth::shim::GetHciLayer()->RegisterCommandComplete(OnCommandComplete);
+  bluetooth::shim::GetHciLayer()->RegisterCommandStatus(OnCommandStatus);
+  return nullptr;
+}
+
+static future_t* hci_module_shut_down(void) {
+  bluetooth::shim::GetHciLayer()->UnregisterCommandComplete();
+  bluetooth::shim::GetHciLayer()->UnregisterCommandStatus();
+  return nullptr;
+}
+
+static void set_data_cb(
+    base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {
+  send_data_upwards = std::move(send_data_cb);
+}
+
+static void transmit_command(BT_HDR* command,
+                             command_complete_cb complete_callback,
+                             command_status_cb status_callback, void* context) {
+  CHECK(command != nullptr);
+  uint8_t* data = command->data + command->offset;
+  size_t len = command->len;
+  CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize));
+
+  // little endian command opcode
+  uint16_t command_op_code = (data[1] << 8 | data[0]);
+  // Gd stack API requires opcode specification and calculates length, so
+  // no need to provide opcode or length here.
+  data += (kCommandOpcodeSize + kCommandLengthSize);
+  len -= (kCommandOpcodeSize + kCommandLengthSize);
+
+  const CommandCallbackData* command_callback_data = new CommandCallbackData{
+      context,
+      complete_callback,
+      status_callback,
+  };
+  bluetooth::shim::GetHciLayer()->TransmitCommand(
+      command_op_code, const_cast<const uint8_t*>(data), len,
+      static_cast<const void*>(command_callback_data));
+}
+
+const hci_t* bluetooth::shim::hci_layer_get_interface() {
+  static bool loaded = false;
+  if (!loaded) {
+    loaded = true;
+    interface.set_data_cb = set_data_cb;
+    interface.transmit_command = transmit_command;
+    interface.transmit_command_futured = nullptr;
+    interface.transmit_downward = nullptr;
+  }
+  return &interface;
+}
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/main/shim/hci_layer.h
similarity index 73%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to main/shim/hci_layer.h
index 8a08509..6b0bbcc 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/main/shim/hci_layer.h
@@ -14,12 +14,19 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+/**
+ * Gd shim layer to legacy hci layer stack
+ */
+#pragma once
+
+#include "hci/include/hci_layer.h"
+
+static const char GD_HCI_MODULE[] = "gd_hci_module";
 
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+const hci_t* hci_layer_get_interface();
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc
new file mode 100644
index 0000000..ccfb879
--- /dev/null
+++ b/main/shim/l2c_api.cc
@@ -0,0 +1,423 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bt_shim_l2cap"
+
+#include "main/shim/l2c_api.h"
+#include "main/shim/l2cap.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+
+static bluetooth::legacy::shim::L2cap shim_l2cap;
+
+/**
+ * Classic Service Registration APIs
+ */
+uint16_t bluetooth::shim::L2CA_Register(uint16_t client_psm,
+                                        tL2CAP_APPL_INFO* callbacks,
+                                        bool enable_snoop) {
+  if (L2C_INVALID_PSM(client_psm)) {
+    LOG_ERROR(LOG_TAG, "%s Invalid classic psm:%hd", __func__, client_psm);
+    return 0;
+  }
+
+  if ((callbacks->pL2CA_ConfigCfm_Cb == nullptr) ||
+      (callbacks->pL2CA_ConfigInd_Cb == nullptr) ||
+      (callbacks->pL2CA_DataInd_Cb == nullptr) ||
+      (callbacks->pL2CA_DisconnectInd_Cb == nullptr)) {
+    LOG_ERROR(LOG_TAG, "%s Invalid classic callbacks psm:%hd", __func__,
+              client_psm);
+    return 0;
+  }
+
+  /**
+   * Check if this is a registration for an outgoing-only connection.
+   */
+  bool is_outgoing_connection_only = callbacks->pL2CA_ConnectInd_Cb == nullptr;
+  uint16_t psm = shim_l2cap.ConvertClientToRealPsm(client_psm,
+                                                   is_outgoing_connection_only);
+
+  if (shim_l2cap.Classic().IsPsmRegistered(psm)) {
+    LOG_ERROR(LOG_TAG, "%s Already registered classic client_psm:%hd psm:%hd",
+              __func__, client_psm, psm);
+    return 0;
+  }
+  shim_l2cap.Classic().RegisterPsm(psm, callbacks);
+
+  LOG_INFO(LOG_TAG, "%s classic client_psm:%hd psm:%hd", __func__, client_psm,
+           psm);
+
+  shim_l2cap.RegisterService(psm, callbacks, enable_snoop);
+
+  return client_psm;
+}
+
+void bluetooth::shim::L2CA_Deregister(uint16_t client_psm) {
+  if (L2C_INVALID_PSM(client_psm)) {
+    LOG_ERROR(LOG_TAG, "%s Invalid classic client_psm:%hd", __func__,
+              client_psm);
+    return;
+  }
+  uint16_t psm = shim_l2cap.ConvertClientToRealPsm(client_psm);
+
+  if (!shim_l2cap.Classic().IsPsmRegistered(psm)) {
+    LOG_ERROR(LOG_TAG,
+              "%s Not previously registered classic client_psm:%hd psm:%hd",
+              __func__, client_psm, psm);
+    return;
+  }
+  shim_l2cap.Classic().UnregisterPsm(psm);
+  shim_l2cap.RemoveClientPsm(psm);
+}
+
+uint16_t bluetooth::shim::L2CA_AllocatePSM(void) {
+  uint16_t psm = shim_l2cap.GetNextDynamicClassicPsm();
+  shim_l2cap.Classic().AllocatePsm(psm);
+  return psm;
+}
+
+uint16_t bluetooth::shim::L2CA_AllocateLePSM(void) {
+  uint16_t psm = shim_l2cap.GetNextDynamicLePsm();
+  shim_l2cap.Le().AllocatePsm(psm);
+  return psm;
+}
+
+void bluetooth::shim::L2CA_FreeLePSM(uint16_t psm) {
+  if (!shim_l2cap.Le().IsPsmAllocated(psm)) {
+    LOG_ERROR(LOG_TAG, "%s Not previously allocated le psm:%hd", __func__, psm);
+    return;
+  }
+  if (!shim_l2cap.Le().IsPsmRegistered(psm)) {
+    LOG_ERROR(LOG_TAG, "%s Must deregister psm before deallocation psm:%hd",
+              __func__, psm);
+    return;
+  }
+  shim_l2cap.Le().DeallocatePsm(psm);
+}
+
+/**
+ * Classic Connection Oriented Channel APIS
+ */
+uint16_t bluetooth::shim::L2CA_ErtmConnectReq(uint16_t psm,
+                                              const RawAddress& raw_address,
+                                              tL2CAP_ERTM_INFO* p_ertm_info) {
+  CHECK(p_ertm_info == nullptr)
+      << "UNIMPLEMENTED set enhanced retransmission mode config";
+  return shim_l2cap.CreateConnection(psm, raw_address);
+}
+
+uint16_t bluetooth::shim::L2CA_ConnectReq(uint16_t psm,
+                                          const RawAddress& raw_address) {
+  return bluetooth::shim::L2CA_ErtmConnectReq(psm, raw_address, nullptr);
+}
+
+bool bluetooth::shim::L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr,
+                                          uint8_t id, uint16_t lcid,
+                                          uint16_t result, uint16_t status,
+                                          tL2CAP_ERTM_INFO* p_ertm_info) {
+  LOG_INFO(LOG_TAG,
+           "UNIMPLEMENTED %s addr:%s id:%hhd lcid:%hd result:%hd status:%hd "
+           "p_ertm_info:%p",
+           __func__, p_bd_addr.ToString().c_str(), id, lcid, result, status,
+           p_ertm_info);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id,
+                                      uint16_t lcid, uint16_t result,
+                                      uint16_t status) {
+  return bluetooth::shim::L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result,
+                                              status, NULL);
+}
+
+bool bluetooth::shim::L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) {
+  return shim_l2cap.ConfigRequest(cid, cfg_info);
+}
+
+bool bluetooth::shim::L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) {
+  return shim_l2cap.ConfigResponse(cid, cfg_info);
+}
+
+bool bluetooth::shim::L2CA_DisconnectReq(uint16_t cid) {
+  return shim_l2cap.DisconnectRequest(cid);
+}
+
+bool bluetooth::shim::L2CA_DisconnectRsp(uint16_t cid) {
+  return shim_l2cap.DisconnectResponse(cid);
+}
+
+/**
+ * Le Connection Oriented Channel APIs
+ */
+uint16_t bluetooth::shim::L2CA_RegisterLECoc(uint16_t psm,
+                                             tL2CAP_APPL_INFO* callbacks) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd callbacks:%p", __func__, psm,
+           callbacks);
+  return 0;
+}
+
+void bluetooth::shim::L2CA_DeregisterLECoc(uint16_t psm) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd", __func__, psm);
+}
+
+uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm,
+                                               const RawAddress& p_bd_addr,
+                                               tL2CAP_LE_CFG_INFO* p_cfg) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd addr:%s p_cfg:%p", __func__, psm,
+           p_bd_addr.ToString().c_str(), p_cfg);
+  return 0;
+}
+
+bool bluetooth::shim::L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr,
+                                           uint8_t id, uint16_t lcid,
+                                           uint16_t result, uint16_t status,
+                                           tL2CAP_LE_CFG_INFO* p_cfg) {
+  LOG_INFO(LOG_TAG,
+           "UNIMPLEMENTED %s addr:%s id:%hhd lcid:%hd result:%hd status:%hd "
+           "p_cfg:%p",
+           __func__, p_bd_addr.ToString().c_str(), id, lcid, result, status,
+           p_cfg);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t lcid,
+                                              tL2CAP_LE_CFG_INFO* peer_cfg) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s lcid:%hd peer_cfg:%p", __func__, lcid,
+           peer_cfg);
+  return false;
+}
+
+/**
+ * Channel Data Writes
+ */
+bool bluetooth::shim::L2CA_SetConnectionCallbacks(
+    uint16_t cid, const tL2CAP_APPL_INFO* callbacks) {
+  LOG_INFO(LOG_TAG, "Unsupported API %s", __func__);
+  return false;
+}
+
+uint8_t bluetooth::shim::L2CA_DataWriteEx(uint16_t cid, BT_HDR* bt_hdr,
+                                          uint16_t flags) {
+  bool write_success = false;
+  switch (flags) {
+    case L2CAP_FLUSHABLE_CH_BASED:
+      write_success = shim_l2cap.Write(cid, bt_hdr);
+      break;
+    case L2CAP_FLUSHABLE_PKT:
+      write_success = shim_l2cap.WriteFlushable(cid, bt_hdr);
+      break;
+    case L2CAP_NON_FLUSHABLE_PKT:
+      write_success = shim_l2cap.WriteNonFlushable(cid, bt_hdr);
+      break;
+  }
+  return write_success ? L2CAP_DW_SUCCESS : L2CAP_DW_FAILED;
+}
+
+uint8_t bluetooth::shim::L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+  return bluetooth::shim::L2CA_DataWriteEx(cid, p_data,
+                                           L2CAP_FLUSHABLE_CH_BASED);
+}
+
+/**
+ * L2cap Layer APIs
+ */
+uint8_t bluetooth::shim::L2CA_SetDesireRole(uint8_t new_role) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+/**
+ * Ping APIs
+ */
+bool bluetooth::shim::L2CA_Ping(const RawAddress& p_bd_addr,
+                                tL2CA_ECHO_RSP_CB* p_callback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s addr:%s p_callback:%p", __func__,
+           p_bd_addr.ToString().c_str(), p_callback);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
+                                tL2CA_ECHO_DATA_CB* p_callback) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s addr:%s p_callback:%p", __func__,
+           p_bd_addr.ToString().c_str(), p_callback);
+  return false;
+}
+
+/**
+ * Link APIs
+ */
+bool bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr,
+                                                  uint16_t timeout,
+                                                  tBT_TRANSPORT transport) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+uint16_t bluetooth::shim::L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+                                                const RawAddress& p_bd_addr) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+bool bluetooth::shim::L2CA_SetAclPriority(const RawAddress& bd_addr,
+                                          uint8_t priority) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SetFlushTimeout(const RawAddress& bd_addr,
+                                           uint16_t flush_tout) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_GetPeerFeatures(const RawAddress& bd_addr,
+                                           uint32_t* p_ext_feat,
+                                           uint8_t* p_chnl_mask) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_GetBDAddrbyHandle(uint16_t handle,
+                                             RawAddress& bd_addr) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/**
+ * Fixed Channel APIs
+ */
+bool bluetooth::shim::L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+                                                tL2CAP_FIXED_CHNL_REG* p_freg) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t fixed_cid,
+                                            const RawAddress& rem_bda) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t fixed_cid,
+                                            const RawAddress& rem_bda,
+                                            uint8_t initiating_phys) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t fixed_cid,
+                                                 const RawAddress& rem_bda,
+                                                 BT_HDR* p_buf) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+bool bluetooth::shim::L2CA_RemoveFixedChnl(uint16_t fixed_cid,
+                                           const RawAddress& rem_bda) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/**
+ * Channel Configuration API
+ */
+bool bluetooth::shim::L2CA_GetCurrentConfig(
+    uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+    tL2CAP_CH_CFG_BITS* p_our_cfg_bits, tL2CAP_CFG_INFO** pp_peer_cfg,
+    tL2CAP_CH_CFG_BITS* p_peer_cfg_bits) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu,
+                                               uint16_t* rcid,
+                                               uint16_t* handle) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+/**
+ * Channel hygiene APIs
+ */
+bool bluetooth::shim::L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid,
+                                          uint16_t* handle) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout,
+                                          bool is_global) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_FlowControl(uint16_t cid, bool data_enabled) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type,
+                                          uint8_t back_track) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SetTxPriority(uint16_t cid,
+                                         tL2CAP_CHNL_PRIORITY priority) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SetChnlDataRate(uint16_t cid,
+                                           tL2CAP_CHNL_DATA_RATE tx,
+                                           tL2CAP_CHNL_DATA_RATE rx) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+uint8_t bluetooth::shim::L2CA_GetChnlFcrMode(uint16_t lcid) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+bool bluetooth::shim::L2CA_SetFixedChannelTout(const RawAddress& rem_bda,
+                                               uint16_t fixed_cid,
+                                               uint16_t idle_tout) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+bool bluetooth::shim::L2CA_SetChnlFlushability(uint16_t cid,
+                                               bool is_flushable) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
+
+uint16_t bluetooth::shim::L2CA_FlushChannel(uint16_t lcid,
+                                            uint16_t num_to_flush) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return 0;
+}
+
+/**
+ * Misc APIs
+ */
+bool bluetooth::shim::L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb,
+                                         const RawAddress& p_bda) {
+  LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+  return false;
+}
diff --git a/main/shim/l2c_api.h b/main/shim/l2c_api.h
new file mode 100644
index 0000000..83f3afa
--- /dev/null
+++ b/main/shim/l2c_api.h
@@ -0,0 +1,874 @@
+/*
+ * 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 <set>
+#include <unordered_map>
+
+#include "stack/include/l2c_api.h"
+#include "stack/l2cap/l2c_int.h"
+
+namespace bluetooth {
+namespace shim {
+
+/*******************************************************************************
+ *
+ * Function         L2CA_Register
+ *
+ * Description      Other layers call this function to register for L2CAP
+ *                  services.
+ *
+ * Returns          PSM to use or zero if error. Typically, the PSM returned
+ *                  is the same as was passed in, but for an outgoing-only
+ *                  connection to a dynamic PSM, a "virtual" PSM is returned
+ *                  and should be used in the calls to L2CA_ConnectReq() and
+ *                  BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                       bool enable_snoop);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_Deregister
+ *
+ * Description      Other layers call this function to deregister for L2CAP
+ *                  services.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void L2CA_Deregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_AllocatePSM
+ *
+ * Description      Other layers call this function to find an unused PSM for
+ *                  L2CAP services.
+ *
+ * Returns          PSM to use.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocatePSM(void);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_AllocateLePSM
+ *
+ * Description      Other layers call this function to find an unused LE PSM for
+ *                  L2CAP services.
+ *
+ * Returns          LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocateLePSM(void);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FreeLePSM
+ *
+ * Description      Free an assigned LE PSM.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void L2CA_FreeLePSM(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConnectReq
+ *
+ * Description      Higher layers call this function to create an L2CAP
+ *                  connection.
+ *                  Note that the connection is not established at this time,
+ *                  but connection establishment gets started. The callback
+ *                  will be invoked when connection establishes or fails.
+ *
+ * Returns          the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConnectRsp
+ *
+ * Description      Higher layers call this function to accept an incoming
+ *                  L2CAP connection, for which they had gotten an connect
+ *                  indication callback.
+ *
+ * Returns          true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
+                     uint16_t result, uint16_t status);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ErtmConnectReq
+ *
+ * Description      Higher layers call this function to create an L2CAP
+ *                  connection that needs to use Enhanced Retransmission Mode.
+ *                  Note that the connection is not established at this time,
+ *                  but connection establishment gets started. The callback
+ *                  will be invoked when connection establishes or fails.
+ *
+ * Returns          the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
+                             tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_RegisterLECoc
+ *
+ * Description      Other layers call this function to register for L2CAP
+ *                  Connection Oriented Channel.
+ *
+ * Returns          PSM to use or zero if error. Typically, the PSM returned
+ *                  is the same as was passed in, but for an outgoing-only
+ *                  connection to a dynamic PSM, a "virtual" PSM is returned
+ *                  and should be used in the calls to L2CA_ConnectLECocReq()
+ *                  and BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_DeregisterLECoc
+ *
+ * Description      Other layers call this function to deregister for L2CAP
+ *                  Connection Oriented Channel.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+void L2CA_DeregisterLECoc(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConnectLECocReq
+ *
+ * Description      Higher layers call this function to create an L2CAP LE COC.
+ *                  Note that the connection is not established at this time,
+ *                  but connection establishment gets started. The callback
+ *                  will be invoked when connection establishes or fails.
+ *
+ * Returns          the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
+                              tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConnectLECocRsp
+ *
+ * Description      Higher layers call this function to accept an incoming
+ *                  L2CAP LE COC connection, for which they had gotten a connect
+ *                  indication callback.
+ *
+ * Returns          true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr, uint8_t id,
+                          uint16_t lcid, uint16_t result, uint16_t status,
+                          tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ *  Function         L2CA_GetPeerLECocConfig
+ *
+ *  Description      Get peers configuration for LE Connection Oriented Channel.
+ *
+ *  Return value:    true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg);
+
+// This function sets the callback routines for the L2CAP connection referred to
+// by |local_cid|. The callback routines can only be modified for outgoing
+// connections established by |L2CA_ConnectReq| or accepted incoming
+// connections. |callbacks| must not be NULL. This function returns true if the
+// callbacks could be updated, false if not (e.g. |local_cid| was not found).
+bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
+                                 const tL2CAP_APPL_INFO* callbacks);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ErtmConnectRsp
+ *
+ * Description      Higher layers call this function to accept an incoming
+ *                  L2CAP connection, for which they had gotten an connect
+ *                  indication callback, and for which the higher layer wants
+ *                  to use Enhanced Retransmission Mode.
+ *
+ * Returns          true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
+                         uint16_t result, uint16_t status,
+                         tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConfigReq
+ *
+ * Description      Higher layers call this function to send configuration.
+ *
+ * Returns          true if configuration sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_ConfigRsp
+ *
+ * Description      Higher layers call this function to send a configuration
+ *                  response.
+ *
+ * Returns          true if configuration response sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_DisconnectReq
+ *
+ * Description      Higher layers call this function to disconnect a channel.
+ *
+ * Returns          true if disconnect sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectReq(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_DisconnectRsp
+ *
+ * Description      Higher layers call this function to acknowledge the
+ *                  disconnection of a channel.
+ *
+ * Returns          void
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectRsp(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_DataWrite
+ *
+ * Description      Higher layers call this function to write data.
+ *
+ * Returns          L2CAP_DW_SUCCESS, if data accepted, else false
+ *                  L2CAP_DW_CONGESTED, if data accepted and the channel is
+ *                                      congested
+ *                  L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_Ping
+ *
+ * Description      Higher layers call this function to send an echo request.
+ *
+ * Returns          true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Ping(const RawAddress& p_bd_addr, tL2CA_ECHO_RSP_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_Echo
+ *
+ * Description      Higher layers call this function to send an echo request
+ *                  with application-specific data.
+ *
+ * Returns          true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
+               tL2CA_ECHO_DATA_CB* p_callback);
+
+// Given a local channel identifier, |lcid|, this function returns the bound
+// remote channel identifier, |rcid|, and the ACL link handle, |handle|. If
+// |lcid| is not known or is invalid, this function returns false and does not
+// modify the values pointed at by |rcid| and |handle|. |rcid| and |handle| may
+// be NULL.
+bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetIdleTimeout
+ *
+ * Description      Higher layers call this function to set the idle timeout for
+ *                  a connection, or for all future connections. The "idle
+ *                  timeout" is the amount of time that a connection can remain
+ *                  up with no L2CAP channels on it. A timeout of zero means
+ *                  that the connection will be torn down immediately when the
+ *                  last channel is removed. A timeout of 0xFFFF means no
+ *                  timeout. Values are in seconds.
+ *
+ * Returns          true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetIdleTimeoutByBdAddr
+ *
+ * Description      Higher layers call this function to set the idle timeout for
+ *                  a connection. The "idle timeout" is the amount of time that
+ *                  a connection can remain up with no L2CAP channels on it.
+ *                  A timeout of zero means that the connection will be torn
+ *                  down immediately when the last channel is removed.
+ *                  A timeout of 0xFFFF means no timeout. Values are in seconds.
+ *                  A bd_addr is the remote BD address. If bd_addr =
+ *                  RawAddress::kAny, then the idle timeouts for all active
+ *                  l2cap links will be changed.
+ *
+ * Returns          true if command succeeded, false if failed
+ *
+ * NOTE             This timeout applies to all logical channels active on the
+ *                  ACL link.
+ ******************************************************************************/
+bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
+                                 tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetTraceLevel
+ *
+ * Description      This function sets the trace level for L2CAP. If called with
+ *                  a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns          the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetTraceLevel(uint8_t trace_level);
+
+/*******************************************************************************
+ *
+ * Function     L2CA_SetDesireRole
+ *
+ * Description  This function sets the desire role for L2CAP.
+ *              If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+ *              HciCreateConnection.
+ *              If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow
+ *              switch on HciCreateConnection.
+ *
+ *              If the new role is a valid role (HCI_ROLE_MASTER or
+ *              HCI_ROLE_SLAVE), the desire role is set to the new value.
+ *              Otherwise, it is not changed.
+ *
+ * Returns      the new (current) role
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetDesireRole(uint8_t new_role);
+
+/*******************************************************************************
+ *
+ * Function     L2CA_LocalLoopbackReq
+ *
+ * Description  This function sets up a CID for local loopback
+ *
+ * Returns      CID of 0 if none.
+ *
+ ******************************************************************************/
+uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+                               const RawAddress& p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function     L2CA_FlushChannel
+ *
+ * Description  This function flushes none, some or all buffers queued up
+ *              for xmission for a particular CID. If called with
+ *              L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+ *              of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+ *              flushes all buffers.  All other values specifies the maximum
+ *              buffers to flush.
+ *
+ * Returns      Number of buffers left queued for that CID
+ *
+ ******************************************************************************/
+uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetAclPriority
+ *
+ * Description      Sets the transmission priority for an ACL channel.
+ *                  (For initial implementation only two values are valid.
+ *                  L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetAclPriority(const RawAddress& bd_addr, uint8_t priority);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_FlowControl
+ *
+ * Description      Higher layers call this function to flow control a channel.
+ *
+ *                  data_enabled - true data flows, false data is stopped
+ *
+ * Returns          true if valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_FlowControl(uint16_t cid, bool data_enabled);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SendTestSFrame
+ *
+ * Description      Higher layers call this function to send a test S-frame.
+ *
+ * Returns          true if valid Channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type, uint8_t back_track);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetTxPriority
+ *
+ * Description      Sets the transmission priority for a channel. (FCR Mode)
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_RegForNoCPEvt
+ *
+ * Description      Register callback for Number of Completed Packets event.
+ *
+ * Input Param      p_cb - callback for Number of completed packets event
+ *                  p_bda - BT address of remote device
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, const RawAddress& p_bda);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetChnlDataRate
+ *
+ * Description      Sets the tx/rx data rate for a channel.
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
+                          tL2CAP_CHNL_DATA_RATE rx);
+
+typedef void(tL2CA_RESERVE_CMPL_CBACK)(void);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetFlushTimeout
+ *
+ * Description      This function set the automatic flush time out in Baseband
+ *                  for ACL-U packets.
+ *                  BdAddr : the remote BD address of ACL link. If it is
+ *                           BT_DB_ANY then the flush time out will be applied
+ *                           to all ACL link.
+ *                  FlushTimeout: flush time out in ms
+ *                           0x0000 : No automatic flush
+ *                           L2CAP_NO_RETRANSMISSION : No retransmission
+ *                           0x0002 - 0xFFFE : flush time out, if
+ *                                             (flush_tout * 8) + 3 / 5) <=
+ *                                             HCI_MAX_AUTOMATIC_FLUSH_TIMEOUT
+ *                                             (in 625us slot).
+ *                                    Otherwise, return false.
+ *                           L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+ *
+ * Returns          true if command succeeded, false if failed
+ *
+ * NOTE             This flush timeout applies to all logical channels active on
+ *                  the ACL link.
+ ******************************************************************************/
+bool L2CA_SetFlushTimeout(const RawAddress& bd_addr, uint16_t flush_tout);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_DataWriteEx
+ *
+ * Description      Higher layers call this function to write data with extended
+ *                  flags.
+ *                  flags : L2CAP_FLUSHABLE_CH_BASED
+ *                          L2CAP_FLUSHABLE_PKT
+ *                          L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Returns          L2CAP_DW_SUCCESS, if data accepted, else false
+ *                  L2CAP_DW_CONGESTED, if data accepted and the channel is
+ *                                      congested
+ *                  L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetChnlFlushability
+ *
+ * Description      Higher layers call this function to set a channels
+ *                  flushability flags
+ *
+ * Returns          true if CID found, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable);
+
+/*******************************************************************************
+ *
+ *  Function         L2CA_GetPeerFeatures
+ *
+ *  Description      Get a peers features and fixed channel map
+ *
+ *  Parameters:      BD address of the peer
+ *                   Pointers to features and channel mask storage area
+ *
+ *  Return value:    true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+                          uint8_t* p_chnl_mask);
+
+/*******************************************************************************
+ *
+ *  Function         L2CA_GetBDAddrbyHandle
+ *
+ *  Description      Get BD address for the given HCI handle
+ *
+ *  Parameters:      HCI handle
+ *                   BD address of the peer
+ *
+ *  Return value:    true if found lcb for the given handle, false otherwise
+ *
+ ******************************************************************************/
+bool L2CA_GetBDAddrbyHandle(uint16_t handle, RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ *  Function         L2CA_GetChnlFcrMode
+ *
+ *  Description      Get the channel FCR mode
+ *
+ *  Parameters:      Local CID
+ *
+ *  Return value:    Channel mode
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetChnlFcrMode(uint16_t lcid);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UcdRegister
+ *
+ *  Description     Register PSM on UCD.
+ *
+ *  Parameters:     tL2CAP_UCD_CB_INFO
+ *
+ *  Return value:   true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdRegister(uint16_t psm, tL2CAP_UCD_CB_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UcdDeregister
+ *
+ *  Description     Deregister PSM on UCD.
+ *
+ *  Parameters:     PSM
+ *
+ *  Return value:   true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDeregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UcdDiscover
+ *
+ *  Description     Discover UCD of remote device.
+ *
+ *  Parameters:     PSM
+ *                  BD_ADDR of remote device
+ *                  info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+ *                              L2CAP_UCD_INFO_TYPE_MTU
+ *
+ *
+ *  Return value:   true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDiscover(uint16_t psm, const RawAddress& rem_bda,
+                      uint8_t info_type);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UcdDataWrite
+ *
+ *  Description     Send UCD to remote device
+ *
+ *  Parameters:     PSM
+ *                  BD Address of remote
+ *                  Pointer to buffer of type BT_HDR
+ *                  flags : L2CAP_FLUSHABLE_CH_BASED
+ *                          L2CAP_FLUSHABLE_PKT
+ *                          L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Return value     L2CAP_DW_SUCCESS, if data accepted
+ *                  L2CAP_DW_FAILED,  if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_UcdDataWrite(uint16_t psm, const RawAddress& rem_bda,
+                           BT_HDR* p_buf, uint16_t flags);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UcdSetIdleTimeout
+ *
+ *  Description     Set UCD Idle timeout.
+ *
+ *  Parameters:     BD Addr
+ *                  Timeout in second
+ *
+ *  Return value:   true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdSetIdleTimeout(const RawAddress& rem_bda, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_UCDSetTxPriority
+ *
+ * Description      Sets the transmission priority for a connectionless channel.
+ *
+ * Returns          true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_UCDSetTxPriority(const RawAddress& rem_bda,
+                           tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_RegisterFixedChannel
+ *
+ *  Description     Register a fixed channel.
+ *
+ *  Parameters:     Fixed Channel #
+ *                  Channel Callbacks and config
+ *
+ *  Return value:   true if registered OK
+ *
+ ******************************************************************************/
+bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+                               tL2CAP_FIXED_CHNL_REG* p_freg);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_ConnectFixedChnl
+ *
+ *  Description     Connect an fixed signalling channel to a remote device.
+ *
+ *  Parameters:     Fixed CID
+ *                  BD Address of remote
+ *
+ *  Return value:   true if connection started
+ *
+ ******************************************************************************/
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr);
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr,
+                           uint8_t initiating_phys);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_SendFixedChnlData
+ *
+ *  Description     Write data on a fixed signalling channel.
+ *
+ *  Parameters:     Fixed CID
+ *                  BD Address of remote
+ *                  Pointer to buffer of type BT_HDR
+ *
+ * Return value     L2CAP_DW_SUCCESS, if data accepted
+ *                  L2CAP_DW_FAILED,  if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
+                                BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_RemoveFixedChnl
+ *
+ *  Description     Remove a fixed channel to a remote device.
+ *
+ *  Parameters:     Fixed CID
+ *                  BD Address of remote
+ *                  Idle timeout to use (or 0xFFFF if don't care)
+ *
+ *  Return value:   true if channel removed
+ *
+ ******************************************************************************/
+bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_SetFixedChannelTout
+ *
+ * Description      Higher layers call this function to set the idle timeout for
+ *                  a fixed channel. The "idle timeout" is the amount of time
+ *                  that a connection can remain up with no L2CAP channels on
+ *                  it. A timeout of zero means that the connection will be torn
+ *                  down immediately when the last channel is removed.
+ *                  A timeout of 0xFFFF means no timeout. Values are in seconds.
+ *                  A bd_addr is the remote BD address. If bd_addr =
+ *                  RawAddress::kAny, then the idle timeouts for all active
+ *                  l2cap links will be changed.
+ *
+ * Returns          true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+bool L2CA_SetFixedChannelTout(const RawAddress& rem_bda, uint16_t fixed_cid,
+                              uint16_t idle_tout);
+
+/*******************************************************************************
+ *
+ * Function     L2CA_GetCurrentConfig
+ *
+ * Description  This function returns configurations of L2CAP channel
+ *              pp_our_cfg : pointer of our saved configuration options
+ *              p_our_cfg_bits : valid config in bitmap
+ *              pp_peer_cfg: pointer of peer's saved configuration options
+ *              p_peer_cfg_bits : valid config in bitmap
+ *
+ * Returns      true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetCurrentConfig(uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+                           tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
+                           tL2CAP_CFG_INFO** pp_peer_cfg,
+                           tL2CAP_CH_CFG_BITS* p_peer_cfg_bits);
+
+/*******************************************************************************
+ *
+ * Function     L2CA_GetConnectionConfig
+ *
+ * Description  This function polulates the mtu, remote cid & lm_handle for
+ *              a given local L2CAP channel
+ *
+ * Returns      true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu, uint16_t* rcid,
+                              uint16_t* handle);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_CancelBleConnectReq
+ *
+ *  Description     Cancel a pending connection attempt to a BLE device.
+ *
+ *  Parameters:     BD Address of remote
+ *
+ *  Return value:   true if connection was cancelled
+ *
+ ******************************************************************************/
+bool L2CA_CancelBleConnectReq(const RawAddress& rem_bda);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_UpdateBleConnParams
+ *
+ *  Description     Update BLE connection parameters.
+ *
+ *  Parameters:     BD Address of remote
+ *
+ *  Return value:   true if update started
+ *
+ ******************************************************************************/
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bdRa, uint16_t min_int,
+                              uint16_t max_int, uint16_t latency,
+                              uint16_t timeout);
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
+                              uint16_t max_int, uint16_t latency,
+                              uint16_t timeout, uint16_t min_ce_len,
+                              uint16_t max_ce_len);
+
+/*******************************************************************************
+ *
+ *  Function        L2CA_EnableUpdateBleConnParams
+ *
+ *  Description     Update BLE connection parameters.
+ *
+ *  Parameters:     BD Address of remote
+ *                  enable flag
+ *
+ *  Return value:   true if update started
+ *
+ ******************************************************************************/
+bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_GetBleConnRole
+ *
+ * Description      This function returns the connection role.
+ *
+ * Returns          link role.
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetBleConnRole(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function         L2CA_GetDisconnectReason
+ *
+ * Description      This function returns the disconnect reason code.
+ *
+ *  Parameters:     BD Address of remote
+ *                  Physical transport for the L2CAP connection (BR/EDR or LE)
+ *
+ * Returns          disconnect reason
+ *
+ ******************************************************************************/
+uint16_t L2CA_GetDisconnectReason(const RawAddress& remote_bda,
+                                  tBT_TRANSPORT transport);
+
+void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
+                                    uint16_t* max_interval,
+                                    uint16_t floor_interval);
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/l2cap.cc b/main/shim/l2cap.cc
new file mode 100644
index 0000000..98db9cb
--- /dev/null
+++ b/main/shim/l2cap.cc
@@ -0,0 +1,383 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "bt_shim_l2cap"
+
+#include <cstdint>
+
+#include "main/shim/entry.h"
+#include "main/shim/l2cap.h"
+#include "main/shim/shim.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+constexpr size_t kBtHdrSize = sizeof(BT_HDR);
+constexpr uint16_t kInvalidConnectionInterfaceDescriptor = 0;
+constexpr bool kDisconnectResponseRequired = false;
+constexpr uint16_t kConnectionSuccess = 0;
+
+bool bluetooth::legacy::shim::PsmData::IsPsmAllocated(uint16_t psm) const {
+  return psm_to_callback_map_.find(psm) != psm_to_callback_map_.end();
+}
+
+bool bluetooth::legacy::shim::PsmData::IsPsmRegistered(uint16_t psm) const {
+  return IsPsmAllocated(psm) && psm_to_callback_map_.at(psm) != nullptr;
+}
+
+void bluetooth::legacy::shim::PsmData::AllocatePsm(uint16_t psm) {
+  RegisterPsm(psm, nullptr);
+}
+
+void bluetooth::legacy::shim::PsmData::RegisterPsm(
+    uint16_t psm, const tL2CAP_APPL_INFO* callbacks) {
+  psm_to_callback_map_[psm] = callbacks;
+}
+
+void bluetooth::legacy::shim::PsmData::UnregisterPsm(uint16_t psm) {
+  psm_to_callback_map_[psm] = nullptr;
+}
+
+void bluetooth::legacy::shim::PsmData::DeallocatePsm(uint16_t psm) {
+  psm_to_callback_map_.erase(psm);
+}
+
+const tL2CAP_APPL_INFO* bluetooth::legacy::shim::PsmData::Callbacks(
+    uint16_t psm) {
+  if (psm_to_callback_map_.find(psm) == psm_to_callback_map_.end()) {
+    LOG_WARN(LOG_TAG, "Accessing unknown psm:%hd:", psm);
+    return nullptr;
+  }
+  return psm_to_callback_map_[psm];
+}
+
+bluetooth::legacy::shim::L2cap::L2cap()
+    : classic_dynamic_psm_(kInitialClassicDynamicPsm),
+      le_dynamic_psm_(kInitialLeDynamicPsm),
+      classic_virtual_psm_(kInitialClassicVirtualPsm) {}
+
+bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Le() {
+  return le_;
+}
+
+bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Classic() {
+  return classic_;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConnectionExists(uint16_t cid) const {
+  return cid_to_psm_map_.find(cid) != cid_to_psm_map_.end();
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm(
+    uint16_t client_psm, bool is_outgoing_only_connection) {
+  if (!is_outgoing_only_connection) {
+    return client_psm;
+  }
+  return GetNextVirtualPsm(client_psm);
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm(
+    uint16_t client_psm) {
+  if (client_psm_to_real_psm_map_.find(client_psm) ==
+      client_psm_to_real_psm_map_.end()) {
+    return client_psm;
+  }
+  return client_psm_to_real_psm_map_.at(client_psm);
+}
+
+void bluetooth::legacy::shim::L2cap::RemoveClientPsm(uint16_t client_psm) {
+  if (client_psm_to_real_psm_map_.find(client_psm) !=
+      client_psm_to_real_psm_map_.end()) {
+    client_psm_to_real_psm_map_.erase(client_psm);
+  }
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextVirtualPsm(uint16_t real_psm) {
+  if (real_psm < kInitialClassicDynamicPsm) {
+    return real_psm;
+  }
+
+  while (Classic().IsPsmAllocated(classic_virtual_psm_)) {
+    classic_virtual_psm_ += 2;
+    if (classic_virtual_psm_ >= kFinalClassicVirtualPsm) {
+      classic_virtual_psm_ = kInitialClassicVirtualPsm;
+    }
+  }
+  return classic_virtual_psm_;
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicLePsm() {
+  while (Le().IsPsmAllocated(le_dynamic_psm_)) {
+    le_dynamic_psm_++;
+    if (le_dynamic_psm_ > kFinalLeDynamicPsm) {
+      le_dynamic_psm_ = kInitialLeDynamicPsm;
+    }
+  }
+  return le_dynamic_psm_;
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicClassicPsm() {
+  while (Classic().IsPsmAllocated(classic_dynamic_psm_)) {
+    classic_dynamic_psm_ += 2;
+    if (classic_dynamic_psm_ > kFinalClassicDynamicPsm) {
+      classic_dynamic_psm_ = kInitialClassicDynamicPsm;
+    } else if (classic_dynamic_psm_ & 0x0100) {
+      /* the upper byte must be even */
+      classic_dynamic_psm_ += 0x0100;
+    }
+
+    /* if psm is in range of reserved BRCM Aware features */
+    if ((BRCM_RESERVED_PSM_START <= classic_dynamic_psm_) &&
+        (classic_dynamic_psm_ <= BRCM_RESERVED_PSM_END)) {
+      classic_dynamic_psm_ = BRCM_RESERVED_PSM_END + 2;
+    }
+  }
+  return classic_dynamic_psm_;
+}
+
+void bluetooth::legacy::shim::L2cap::RegisterService(
+    uint16_t psm, const tL2CAP_APPL_INFO* callbacks, bool enable_snoop) {
+  LOG_DEBUG(LOG_TAG, "Registering service on psm:%hd", psm);
+
+  if (!enable_snoop) {
+    LOG_WARN(LOG_TAG, "UNIMPLEMENTED Cannot disable snooping on psm:%d", psm);
+  }
+
+  Classic().RegisterPsm(psm, callbacks);
+
+  std::promise<void> register_completed;
+  auto completed = register_completed.get_future();
+  bluetooth::shim::GetL2cap()->RegisterService(
+      psm,
+      std::bind(
+          &bluetooth::legacy::shim::L2cap::OnRemoteInitiatedConnectionCreated,
+          this, std::placeholders::_1, std::placeholders::_2,
+          std::placeholders::_3),
+      std::move(register_completed));
+  completed.wait();
+  LOG_DEBUG(LOG_TAG, "Successfully registered service on psm:%hd", psm);
+}
+
+void bluetooth::legacy::shim::L2cap::OnRemoteInitiatedConnectionCreated(
+    std::string string_address, uint16_t psm, uint16_t cid) {
+  RawAddress raw_address;
+  RawAddress::FromString(string_address, raw_address);
+
+  LOG_DEBUG(LOG_TAG,
+            "Sending connection indicator to upper stack from device:%s "
+            "psm:%hd cid:%hd",
+            string_address.c_str(), psm, cid);
+
+  CHECK(!ConnectionExists(cid));
+  cid_to_psm_map_[cid] = psm;
+  SetCallbacks(cid, Classic().Callbacks(psm));
+  const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm);
+  CHECK(callbacks != nullptr);
+  callbacks->pL2CA_ConnectInd_Cb(raw_address, cid, psm /* UNUSED */,
+                                 0 /* UNUSED */);
+}
+
+void bluetooth::legacy::shim::L2cap::UnregisterService(uint16_t psm) {
+  if (!Classic().IsPsmRegistered(psm)) {
+    LOG_WARN(LOG_TAG,
+             "Service must be registered in order to unregister psm:%hd", psm);
+    return;
+  }
+  LOG_DEBUG(LOG_TAG, "Unregistering service on psm:%hd", psm);
+  // TODO(cmanton) Check for open channels before unregistering
+  bluetooth::shim::GetL2cap()->UnregisterService(psm);
+  Classic().UnregisterPsm(psm);
+  Classic().DeallocatePsm(psm);
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::CreateConnection(
+    uint16_t psm, const RawAddress& raw_address) {
+  if (!Classic().IsPsmRegistered(psm)) {
+    LOG_WARN(LOG_TAG, "Service must be registered in order to connect psm:%hd",
+             psm);
+    return kInvalidConnectionInterfaceDescriptor;
+  }
+
+  std::promise<uint16_t> connect_completed;
+  auto completed = connect_completed.get_future();
+  LOG_DEBUG(LOG_TAG,
+            "Starting local initiated connection to psm:%hd address:%s", psm,
+            raw_address.ToString().c_str());
+
+  bluetooth::shim::GetL2cap()->CreateConnection(
+      psm, raw_address.ToString(),
+      std::bind(
+          &bluetooth::legacy::shim::L2cap::OnLocalInitiatedConnectionCreated,
+          this, std::placeholders::_1, std::placeholders::_2,
+          std::placeholders::_3),
+      std::move(connect_completed));
+
+  uint16_t cid = completed.get();
+  if (cid == kInvalidConnectionInterfaceDescriptor) {
+    LOG_WARN(LOG_TAG,
+             "Failed to allocate resources to connect to psm:%hd address:%s",
+             psm, raw_address.ToString().c_str());
+  } else {
+    LOG_DEBUG(LOG_TAG,
+              "Successfully started connection to psm:%hd address:%s"
+              " connection_interface_descriptor:%hd",
+              psm, raw_address.ToString().c_str(), cid);
+    CHECK(!ConnectionExists(cid));
+    cid_to_psm_map_[cid] = psm;
+    SetCallbacks(cid, Classic().Callbacks(psm));
+  }
+  return cid;
+}
+
+void bluetooth::legacy::shim::L2cap::OnLocalInitiatedConnectionCreated(
+    std::string string_address, uint16_t psm, uint16_t cid) {
+  LOG_DEBUG(LOG_TAG,
+            "Sending connection confirm to the upper stack but really "
+            "a connection to %s has already been done cid:%hd",
+            string_address.c_str(), cid);
+  // TODO(cmanton) Make sure the device is correct for locally initiated
+  const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm);
+  CHECK(callbacks != nullptr);
+  callbacks->pL2CA_ConnectCfm_Cb(cid, kConnectionSuccess);
+};
+
+bool bluetooth::legacy::shim::L2cap::Write(uint16_t cid, BT_HDR* bt_hdr) {
+  CHECK(bt_hdr != nullptr);
+  const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+  size_t len = bt_hdr->len;
+  if (!ConnectionExists(cid) || len == 0) {
+    return false;
+  }
+  LOG_DEBUG(LOG_TAG, "Writing data cid:%hd len:%zd", cid, len);
+  bluetooth::shim::GetL2cap()->Write(cid, data, len);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::WriteFlushable(uint16_t cid,
+                                                    BT_HDR* bt_hdr) {
+  CHECK(bt_hdr != nullptr);
+  const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+  size_t len = bt_hdr->len;
+  if (!ConnectionExists(cid) || len == 0) {
+    return false;
+  }
+  bluetooth::shim::GetL2cap()->WriteFlushable(cid, data, len);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::WriteNonFlushable(uint16_t cid,
+                                                       BT_HDR* bt_hdr) {
+  CHECK(bt_hdr != nullptr);
+  const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+  size_t len = bt_hdr->len;
+  if (!ConnectionExists(cid) || len == 0) {
+    return false;
+  }
+  bluetooth::shim::GetL2cap()->WriteNonFlushable(cid, data, len);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::SetCallbacks(
+    uint16_t cid, const tL2CAP_APPL_INFO* callbacks) {
+  CHECK(callbacks != nullptr);
+  CHECK(ConnectionExists(cid));
+  LOG_ASSERT(cid_to_callback_map_.find(cid) == cid_to_callback_map_.end())
+      << "Already have callbacks registered for "
+         "connection_interface_descriptor:"
+      << cid;
+  cid_to_callback_map_[cid] = callbacks;
+
+  bluetooth::shim::GetL2cap()->SetReadDataReadyCallback(
+      cid, [this](uint16_t cid, std::vector<const uint8_t> data) {
+        LOG_DEBUG(LOG_TAG, "OnDataReady cid:%hd len:%zd", cid, data.size());
+        BT_HDR* bt_hdr =
+            static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+        std::copy(data.begin(), data.end(), bt_hdr->data);
+        bt_hdr->len = data.size();
+        CHECK(cid_to_callback_map_.find(cid) != cid_to_callback_map_.end());
+        cid_to_callback_map_[cid]->pL2CA_DataInd_Cb(cid, bt_hdr);
+      });
+
+  bluetooth::shim::GetL2cap()->SetConnectionClosedCallback(
+      cid, [this](uint16_t cid, int error_code) {
+        LOG_DEBUG(LOG_TAG, "OnChannel closed callback cid:%hd", cid);
+        CHECK(cid_to_callback_map_.find(cid) != cid_to_callback_map_.end());
+        cid_to_callback_map_[cid]->pL2CA_DisconnectInd_Cb(
+            cid, kDisconnectResponseRequired);
+        cid_to_callback_map_.erase(cid);
+        cid_to_psm_map_.erase(cid);
+      });
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConnectResponse(
+    const RawAddress& raw_address, uint8_t signal_id, uint16_t cid,
+    uint16_t result, uint16_t status, tL2CAP_ERTM_INFO* ertm_info) {
+  CHECK(ConnectionExists(cid));
+  LOG_DEBUG(LOG_TAG,
+            "%s Silently dropping client connect response as channel is "
+            "already connected",
+            __func__);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConfigRequest(
+    uint16_t cid, const tL2CAP_CFG_INFO* config_info) {
+  CHECK(ConnectionExists(cid));
+  LOG_INFO(LOG_TAG, "Received config request from upper layer cid:%hd", cid);
+
+  bluetooth::shim::GetL2cap()->SendLoopbackResponse([this, cid]() {
+    CHECK(ConnectionExists(cid));
+    const tL2CAP_APPL_INFO* callbacks = cid_to_callback_map_[cid];
+    CHECK(callbacks != nullptr);
+    tL2CAP_CFG_INFO cfg_info{
+        .result = L2CAP_CFG_OK,
+        .mtu_present = false,
+        .qos_present = false,
+        .flush_to_present = false,
+        .fcr_present = false,
+        .fcs_present = false,
+        .ext_flow_spec_present = false,
+        .flags = 0,
+    };
+    callbacks->pL2CA_ConfigCfm_Cb(cid, &cfg_info);
+    callbacks->pL2CA_ConfigInd_Cb(cid, &cfg_info);
+  });
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConfigResponse(
+    uint16_t cid, const tL2CAP_CFG_INFO* config_info) {
+  CHECK(ConnectionExists(cid));
+  LOG_DEBUG(
+      LOG_TAG,
+      "%s Silently dropping client config response as channel is already open",
+      __func__);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::DisconnectRequest(uint16_t cid) {
+  CHECK(ConnectionExists(cid));
+  cid_to_callback_map_.erase(cid);
+  bluetooth::shim::GetL2cap()->CloseConnection(cid);
+  return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::DisconnectResponse(uint16_t cid) {
+  LOG_DEBUG(LOG_TAG,
+            "%s Silently dropping client disconnect response as channel is "
+            "already disconnected",
+            __func__);
+  return true;
+}
diff --git a/main/shim/l2cap.h b/main/shim/l2cap.h
new file mode 100644
index 0000000..2fbe0d6
--- /dev/null
+++ b/main/shim/l2cap.h
@@ -0,0 +1,113 @@
+/*
+ * 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 <cstdint>
+#include <unordered_map>
+
+#include "stack/include/l2c_api.h"
+
+namespace bluetooth {
+namespace legacy {
+namespace shim {
+
+static constexpr uint16_t kInitialClassicDynamicPsm = 0x1001;
+static constexpr uint16_t kFinalClassicDynamicPsm = 0xfeff;
+static constexpr uint16_t kInitialClassicVirtualPsm = kInitialClassicDynamicPsm;
+static constexpr uint16_t kFinalClassicVirtualPsm = 0x8000;
+static constexpr uint16_t kInitialLeDynamicPsm = 0x0080;
+static constexpr uint16_t kFinalLeDynamicPsm = 0x00ff;
+
+using PsmData = struct {
+  bool IsPsmAllocated(uint16_t psm) const;
+  bool IsPsmRegistered(uint16_t psm) const;
+
+  void AllocatePsm(uint16_t psm);
+  void RegisterPsm(uint16_t psm, const tL2CAP_APPL_INFO* callbacks);
+
+  void UnregisterPsm(uint16_t psm);
+  void DeallocatePsm(uint16_t psm);
+
+  const tL2CAP_APPL_INFO* Callbacks(uint16_t psm);
+
+ private:
+  std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> psm_to_callback_map_;
+};
+
+class L2cap {
+ public:
+  void RegisterService(uint16_t psm, const tL2CAP_APPL_INFO* callbacks,
+                       bool enable_snoop);
+  void UnregisterService(uint16_t psm);
+
+  uint16_t CreateConnection(uint16_t psm, const RawAddress& raw_address);
+
+  bool Write(uint16_t cid, BT_HDR* bt_hdr);
+  bool WriteFlushable(uint16_t cid, BT_HDR* bt_hdr);
+  bool WriteNonFlushable(uint16_t cid, BT_HDR* bt_hdr);
+
+  void OnLocalInitiatedConnectionCreated(std::string string_address,
+                                         uint16_t psm, uint16_t cid);
+  void OnRemoteInitiatedConnectionCreated(std::string string_addresss,
+                                          uint16_t psm, uint16_t cid);
+
+  uint16_t GetNextDynamicClassicPsm();
+  uint16_t GetNextDynamicLePsm();
+
+  uint16_t ConvertClientToRealPsm(uint16_t psm,
+                                  bool is_outgoing_only_connection);
+  uint16_t ConvertClientToRealPsm(uint16_t psm);
+  void RemoveClientPsm(uint16_t client_psm);
+
+  // Legacy API entry points
+  bool ConnectResponse(const RawAddress& raw_address, uint8_t signal_id,
+                       uint16_t cid, uint16_t result, uint16_t status,
+                       tL2CAP_ERTM_INFO* ertm_info);
+  bool ConfigRequest(uint16_t cid, const tL2CAP_CFG_INFO* config_info);
+  bool ConfigResponse(uint16_t cid, const tL2CAP_CFG_INFO* config_info);
+  bool DisconnectRequest(uint16_t cid);
+  bool DisconnectResponse(uint16_t cid);
+
+  L2cap();
+
+  PsmData& Classic();
+  PsmData& Le();
+
+ private:
+  uint16_t GetNextVirtualPsm(uint16_t real_psm);
+  bool SetCallbacks(uint16_t cid, const tL2CAP_APPL_INFO* callbacks);
+
+  PsmData classic_;
+  PsmData le_;
+
+  bool ConnectionExists(uint16_t cid) const;
+
+  uint16_t classic_dynamic_psm_;
+  uint16_t le_dynamic_psm_;
+  uint16_t classic_virtual_psm_;
+
+  std::unordered_map<uint16_t,
+                     std::function<void(std::function<void(uint16_t c)>)>>
+      cid_to_postable_map_;
+  std::unordered_map<uint16_t, uint16_t> cid_to_psm_map_;
+  std::unordered_map<uint16_t, uint16_t> client_psm_to_real_psm_map_;
+  std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> cid_to_callback_map_;
+};
+
+}  // namespace shim
+}  // namespace legacy
+}  // namespace bluetooth
diff --git a/main/shim/l2cap_test.cc b/main/shim/l2cap_test.cc
new file mode 100644
index 0000000..bf28f3c
--- /dev/null
+++ b/main/shim/l2cap_test.cc
@@ -0,0 +1,331 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <cstdint>
+
+#define LOG_TAG "bt_shim_test"
+
+#include "osi/include/log.h"
+#include "shim/l2cap.h"
+#include "shim/test_stack.h"
+#include "types/raw_address.h"
+
+TestStack test_stack_;
+
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+  return (bluetooth::shim::IStack*)&test_stack_;
+}
+
+namespace bluetooth {
+namespace legacy {
+
+namespace {
+
+constexpr uint16_t kPsm = 123;
+constexpr uint16_t kCid = 987;
+constexpr size_t kDataBufferSize = 1024;
+
+uint8_t bt_hdr_data[] = {
+    0x00, 0x00,                                     /* event */
+    0x08, 0x00,                                     /* len */
+    0x00, 0x00,                                     /* offset */
+    0x00, 0x00,                                     /* layer specific */
+    0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, /* data */
+    0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, /* data */
+};
+
+class L2capTest;
+L2capTest* l2cap_test_ = nullptr;
+
+class L2capTest : public ::testing::Test {
+ public:
+  static shim::L2cap* l2cap_;
+
+  struct {
+    int L2caConnectCfmCb;
+    int L2caConnectPndCb;
+    int L2caConfigIndCb;
+    int L2caConfigCfmCb;
+    int L2caDisconnectIndCb;
+    int L2caDisconnectCfmCb;
+    int L2caQosViolationIndCb;
+    int L2caDataIndCb;
+    int L2caCongestionStatusCb;
+    int L2caTxCompleteCb;
+    int L2caCreditsReceivedCb;
+  } cnt_{
+      .L2caConnectCfmCb = 0,
+      .L2caConnectPndCb = 0,
+      .L2caConfigIndCb = 0,
+      .L2caConfigCfmCb = 0,
+      .L2caDisconnectIndCb = 0,
+      .L2caDisconnectCfmCb = 0,
+      .L2caQosViolationIndCb = 0,
+      .L2caDataIndCb = 0,
+      .L2caCongestionStatusCb = 0,
+      .L2caTxCompleteCb = 0,
+      .L2caCreditsReceivedCb = 0,
+  };
+
+ protected:
+  void SetUp() override {
+    l2cap_ = new shim::L2cap();
+    l2cap_test_ = this;
+  }
+
+  void TearDown() override {
+    delete l2cap_;
+    l2cap_ = nullptr;
+  }
+
+  uint8_t data_buffer_[kDataBufferSize];
+};
+
+shim::L2cap* L2capTest::l2cap_ = nullptr;
+// Indication of remotely initiated connection response sent
+void L2caConnectIndCb(const RawAddress& raw_address, uint16_t a, uint16_t b,
+                      uint8_t c) {
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated connection request completed
+void L2caConnectCfmCb(uint16_t cid, uint16_t result) {
+  l2cap_test_->cnt_.L2caConnectCfmCb++;
+  LOG_INFO(LOG_TAG, "%s cid:%hd result:%hd", __func__, cid, result);
+}
+
+void L2caConnectPndCb(uint16_t cid) {
+  l2cap_test_->cnt_.L2caConnectPndCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated configuration response sent
+void L2caConfigIndCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+  l2cap_test_->cnt_.L2caConfigIndCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated config request completed
+void L2caConfigCfmCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+  l2cap_test_->cnt_.L2caConfigCfmCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated disconnection response sent
+void L2caDisconnectIndCb(uint16_t cid, bool needs_ack) {
+  l2cap_test_->cnt_.L2caDisconnectIndCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated disconnect request completed
+void L2caDisconnectCfmCb(uint16_t cid, uint16_t result) {
+  l2cap_test_->cnt_.L2caDisconnectCfmCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caQosViolationIndCb(const RawAddress& raw_address) {
+  l2cap_test_->cnt_.L2caQosViolationIndCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caDataIndCb(uint16_t cid, BT_HDR* bt_hdr) {
+  l2cap_test_->cnt_.L2caDataIndCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCongestionStatusCb(uint16_t cid, bool is_congested) {
+  l2cap_test_->cnt_.L2caCongestionStatusCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caTxCompleteCb(uint16_t cid, uint16_t sdu_cnt) {
+  l2cap_test_->cnt_.L2caTxCompleteCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCreditsReceivedCb(uint16_t cid, uint16_t credits_received,
+                           uint16_t credit_count) {
+  l2cap_test_->cnt_.L2caCreditsReceivedCb++;
+  LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+tL2CAP_APPL_INFO test_callbacks{
+    .pL2CA_ConnectInd_Cb = L2caConnectIndCb,
+    .pL2CA_ConnectCfm_Cb = L2caConnectCfmCb,
+    .pL2CA_ConnectPnd_Cb = L2caConnectPndCb,
+    .pL2CA_ConfigInd_Cb = L2caConfigIndCb,
+    .pL2CA_ConfigCfm_Cb = L2caConfigCfmCb,
+    .pL2CA_DisconnectInd_Cb = L2caDisconnectIndCb,
+    .pL2CA_DisconnectCfm_Cb = L2caDisconnectCfmCb,
+    .pL2CA_QoSViolationInd_Cb = L2caQosViolationIndCb,
+    .pL2CA_DataInd_Cb = L2caDataIndCb,
+    .pL2CA_CongestionStatus_Cb = L2caCongestionStatusCb,
+    .pL2CA_TxComplete_Cb = L2caTxCompleteCb,
+    .pL2CA_CreditsReceived_Cb = L2caCreditsReceivedCb,
+};
+
+TEST_F(L2capTest, RegisterService) {
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+  CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
+}
+
+TEST_F(L2capTest, UnregisterService) {
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+  CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
+  l2cap_->UnregisterService(kPsm);
+  CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 0);
+}
+
+TEST_F(L2capTest, CreateConnection_NotRegistered) {
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid == 0);
+}
+
+TEST_F(L2capTest, CreateConnection_Registered) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+}
+
+TEST_F(L2capTest, CreateConnection_ConnectResponse) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  CHECK(l2cap_->ConnectResponse(raw_address, 0, cid, 0, 0, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_ConfigRequest) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  // Simulate a successful connection response
+  l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+  CHECK(cnt_.L2caConnectCfmCb == 1);
+
+  CHECK(l2cap_->ConfigRequest(cid, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_ConfigResponse) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  // Simulate a successful connection response
+  l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+  CHECK(cnt_.L2caConnectCfmCb == 1);
+
+  CHECK(l2cap_->ConfigResponse(cid, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_DisconnectRequest) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  // Simulate a successful connection response
+  l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+  CHECK(cnt_.L2caConnectCfmCb == 1);
+
+  CHECK(l2cap_->DisconnectRequest(cid));
+}
+
+TEST_F(L2capTest, CreateConnection_DisconnectResponse) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  // Simulate a successful connection response
+  l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+  CHECK(cnt_.L2caConnectCfmCb == 1);
+
+  CHECK(l2cap_->DisconnectResponse(cid));
+}
+
+TEST_F(L2capTest, CreateConnection_WithHandshake) {
+  test_stack_.test_l2cap_.cid_ = kCid;
+  l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+  RawAddress raw_address;
+  std::string string_address("11:22:33:44:55:66");
+  RawAddress::FromString(string_address, raw_address);
+  uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+  CHECK(cid != 0);
+
+  // Simulate a successful connection response
+  l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+  CHECK(cnt_.L2caConnectCfmCb == 1);
+
+  CHECK(l2cap_->ConfigRequest(cid, nullptr) == true);
+  CHECK(cnt_.L2caConfigCfmCb == 1);
+  CHECK(cnt_.L2caConfigIndCb == 1);
+
+  BT_HDR* bt_hdr = (BT_HDR*)bt_hdr_data;
+
+  test_stack_.test_l2cap_.data_buffer_ = data_buffer_;
+  test_stack_.test_l2cap_.data_buffer_size_ = kDataBufferSize;
+
+  l2cap_->Write(cid, bt_hdr);
+
+  CHECK(data_buffer_[0] == 0x11);
+  CHECK(data_buffer_[1] == 0x22);
+  CHECK(data_buffer_[2] == 0x33);
+  CHECK(data_buffer_[3] == 0x44);
+  CHECK(data_buffer_[4] == 0x55);
+  CHECK(data_buffer_[5] == 0x66);
+  CHECK(data_buffer_[6] == 0x77);
+  CHECK(data_buffer_[7] == 0x88);
+  CHECK(data_buffer_[8] == 0x00);
+}
+
+}  // namespace
+}  // namespace legacy
+}  // namespace bluetooth
diff --git a/main/shim/shim.cc b/main/shim/shim.cc
new file mode 100644
index 0000000..9af17d6
--- /dev/null
+++ b/main/shim/shim.cc
@@ -0,0 +1,42 @@
+/*
+ * 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 <cstdint>
+
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/properties.h"
+
+static const char* kPropertyKey = "bluetooth.gd.enabled";
+
+static bool gd_shim_enabled_ = false;
+static bool gd_shim_property_checked_ = false;
+
+EXPORT_SYMBOL extern const module_t gd_shim_module = {
+    .name = GD_SHIM_MODULE,
+    .init = nullptr,
+    .start_up = bluetooth::shim::StartGabeldorscheStack,
+    .shut_down = bluetooth::shim::StopGabeldorscheStack,
+    .clean_up = NULL,
+    .dependencies = {NULL}};
+
+bool bluetooth::shim::is_gd_shim_enabled() {
+  if (!gd_shim_property_checked_) {
+    gd_shim_property_checked_ = true;
+    gd_shim_enabled_ = (osi_property_get_int32(kPropertyKey, 0) == 1);
+  }
+  return gd_shim_enabled_;
+}
diff --git a/gd/l2cap/classic_fixed_channel_service.cc b/main/shim/shim.h
similarity index 69%
copy from gd/l2cap/classic_fixed_channel_service.cc
copy to main/shim/shim.h
index 8a08509..38fb208 100644
--- a/gd/l2cap/classic_fixed_channel_service.cc
+++ b/main/shim/shim.h
@@ -14,12 +14,20 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic_fixed_channel_service.h"
+#pragma once
+
+/**
+ * Gabeldorsche related legacy-only-stack-side expansion and support code.
+ */
+#include "btcore/include/module.h"
+#include "main/shim/entry.h"
+
+static const char GD_SHIM_MODULE[] = "gd_shim_module";
 
 namespace bluetooth {
-namespace l2cap {
+namespace shim {
 
-void ClassicFixedChannelService::Unregister(OnUnregisteredCallback on_unregistered) {}
+bool is_gd_shim_enabled();
 
-}  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/main/shim/test_stack.cc b/main/shim/test_stack.cc
new file mode 100644
index 0000000..9d38541
--- /dev/null
+++ b/main/shim/test_stack.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 <cstdint>
+#include <future>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+#include "main/shim/test_stack.h"
+#include "osi/include/log.h"
+
+#define ASSERT(condition)                                    \
+  do {                                                       \
+    if (!(condition)) {                                      \
+      LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \
+    }                                                        \
+  } while (false)
+
+void TestGdShimL2cap::RegisterService(
+    uint16_t psm, bluetooth::shim::ConnectionOpenCallback on_open,
+    std::promise<void> completed) {
+  completed.set_value();
+  registered_service_.insert(psm);
+}
+
+void TestGdShimL2cap::UnregisterService(uint16_t psm) {
+  registered_service_.erase(psm);
+}
+
+void TestGdShimL2cap::CreateConnection(
+    uint16_t psm, const std::string address,
+    bluetooth::shim::ConnectionOpenCallback on_open,
+    std::promise<uint16_t> completed) {
+  completed.set_value(cid_);
+}
+
+void TestGdShimL2cap::CloseConnection(uint16_t cid) {}
+
+void TestGdShimL2cap::SetReadDataReadyCallback(
+    uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) {}
+
+void TestGdShimL2cap::SetConnectionClosedCallback(
+    uint16_t cid, bluetooth::shim::ConnectionClosedCallback on_closed) {}
+
+void TestGdShimL2cap::Write(uint16_t cid, const uint8_t* data, size_t len) {
+  ASSERT(data_buffer_ != nullptr);
+  ASSERT(data_buffer_size_ > len);
+  memcpy(data_buffer_, data, len);
+}
+
+void TestGdShimL2cap::WriteFlushable(uint16_t cid, const uint8_t* data,
+                                     size_t len) {}
+
+void TestGdShimL2cap::WriteNonFlushable(uint16_t cid, const uint8_t* data,
+                                        size_t len) {}
+
+void TestGdShimL2cap::SendLoopbackResponse(std::function<void()> function) {
+  function();
+}
+
+void TestStack::Start() {}
+
+void TestStack::Stop() {}
+
+bluetooth::shim::IAdvertising* TestStack::GetAdvertising() { return nullptr; }
+
+bluetooth::shim::IController* TestStack::GetController() { return nullptr; }
+
+bluetooth::shim::IConnectability* TestStack::GetConnectability() {
+  return nullptr;
+}
+
+bluetooth::shim::IDiscoverability* TestStack::GetDiscoverability() {
+  return nullptr;
+}
+
+bluetooth::shim::IHciLayer* TestStack::GetHciLayer() { return nullptr; }
+
+bluetooth::shim::IInquiry* TestStack::GetInquiry() { return nullptr; }
+
+bluetooth::shim::IL2cap* TestStack::GetL2cap() { return &test_l2cap_; }
+
+bluetooth::shim::IName* TestStack::GetName() { return nullptr; }
+
+bluetooth::shim::IPage* TestStack::GetPage() { return nullptr; }
+
+bluetooth::shim::IScanning* TestStack::GetScanning() { return nullptr; }
diff --git a/main/shim/test_stack.h b/main/shim/test_stack.h
new file mode 100644
index 0000000..92027b1
--- /dev/null
+++ b/main/shim/test_stack.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <cstdint>
+#include <future>
+#include <set>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+
+class TestGdShimL2cap : public bluetooth::shim::IL2cap {
+ public:
+  uint16_t cid_{0};
+  bool write_success_{false};
+  bool is_congested_{false};
+  uint8_t* data_buffer_{nullptr};
+  size_t data_buffer_size_{0};
+  std::set<uint16_t /* psm */> registered_service_;
+
+  void RegisterService(uint16_t psm,
+                       bluetooth::shim::ConnectionOpenCallback on_open,
+                       std::promise<void> completed) override;
+  void UnregisterService(uint16_t psm);
+  void CreateConnection(uint16_t psm, const std::string address,
+                        bluetooth::shim::ConnectionOpenCallback on_open,
+                        std::promise<uint16_t> completed) override;
+  void CloseConnection(uint16_t cid);
+  void SetReadDataReadyCallback(
+      uint16_t cid,
+      bluetooth::shim::ReadDataReadyCallback on_data_ready) override;
+  void SetConnectionClosedCallback(
+      uint16_t cid,
+      bluetooth::shim::ConnectionClosedCallback on_closed) override;
+  void Write(uint16_t cid, const uint8_t* data, size_t len) override;
+  void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+  void WriteNonFlushable(uint16_t cid, const uint8_t* data,
+                         size_t len) override;
+  void SendLoopbackResponse(std::function<void()>) override;
+};
+
+class TestStack : public bluetooth::shim::IStack {
+ public:
+  TestStack() = default;
+
+  bluetooth::shim::IAdvertising* GetAdvertising();
+  bluetooth::shim::IController* GetController();
+  bluetooth::shim::IConnectability* GetConnectability();
+  bluetooth::shim::IDiscoverability* GetDiscoverability();
+  bluetooth::shim::IHciLayer* GetHciLayer();
+  bluetooth::shim::IInquiry* GetInquiry();
+  bluetooth::shim::IL2cap* GetL2cap();
+  bluetooth::shim::IName* GetName();
+  bluetooth::shim::IPage* GetPage();
+  bluetooth::shim::IScanning* GetScanning();
+
+  TestGdShimL2cap test_l2cap_;
+
+  void Start();
+  void Stop();
+};
diff --git a/osi/include/config.h b/osi/include/config.h
index 55adecb..47c3a3e 100644
--- a/osi/include/config.h
+++ b/osi/include/config.h
@@ -49,6 +49,9 @@
 // file on the filesystem.
 std::unique_ptr<config_t> config_new(const char* filename);
 
+// Read the checksum from the |filename|
+std::string checksum_read(const char* filename);
+
 // Clones |src|, including all of it's sections, keys, and values.
 // Returns a new config which is a copy and separated from the original;
 // changes to the new config are not reflected in any way in the original.
@@ -133,3 +136,8 @@
 // |config_save|, all comments and special formatting in the original file will
 // be lost. Neither |config| nor |filename| may be NULL.
 bool config_save(const config_t& config, const std::string& filename);
+
+// Saves the encrypted |checksum| of config file to a given |filename| Note
+// that this could be a destructive operation: if |filename| already exists,
+// it will be overwritten.
+bool checksum_save(const std::string& checksum, const std::string& filename);
diff --git a/osi/src/alarm.cc b/osi/src/alarm.cc
index 30e4ed8..bc1eee5 100644
--- a/osi/src/alarm.cc
+++ b/osi/src/alarm.cc
@@ -246,7 +246,7 @@
   CHECK(alarms != NULL);
   if (!alarm) return;
 
-  std::shared_ptr<std::recursive_mutex> local_mutex_ref = alarm->callback_mutex;
+  std::shared_ptr<std::recursive_mutex> local_mutex_ref;
   {
     std::lock_guard<std::mutex> lock(alarms_mutex);
     local_mutex_ref = alarm->callback_mutex;
diff --git a/osi/src/config.cc b/osi/src/config.cc
index e937959..de7e6e6 100644
--- a/osi/src/config.cc
+++ b/osi/src/config.cc
@@ -18,7 +18,7 @@
 
 #include "osi/include/config.h"
 
-#include <base/files/file_path.h>
+#include <base/files/file_util.h>
 #include <base/logging.h>
 #include <ctype.h>
 #include <errno.h>
@@ -84,6 +84,19 @@
   return config;
 }
 
+std::string checksum_read(const char* filename) {
+  base::FilePath path(filename);
+  if (!base::PathExists(path)) {
+    LOG(ERROR) << __func__ << ": unable to locate file '" << filename << "'";
+    return "";
+  }
+  std::string encrypted_hash;
+  if (!base::ReadFileToString(path, &encrypted_hash)) {
+    LOG(ERROR) << __func__ << ": unable to read file '" << filename << "'";
+  }
+  return encrypted_hash;
+}
+
 std::unique_ptr<config_t> config_new_clone(const config_t& src) {
   std::unique_ptr<config_t> ret = config_new_empty();
 
@@ -332,6 +345,107 @@
   return false;
 }
 
+bool checksum_save(const std::string& checksum, const std::string& filename) {
+  CHECK(!checksum.empty()) << __func__ << ": checksum cannot be empty";
+  CHECK(!filename.empty()) << __func__ << ": filename cannot be empty";
+
+  // Steps to ensure content of config checksum file gets to disk:
+  //
+  // 1) Open and write to temp file (e.g.
+  // bt_config.conf.encrypted-checksum.new). 2) Sync the temp file to disk with
+  // fsync(). 3) Rename temp file to actual config checksum file (e.g.
+  // bt_config.conf.encrypted-checksum).
+  //    This ensures atomic update.
+  // 4) Sync directory that has the conf file with fsync().
+  //    This ensures directory entries are up-to-date.
+  FILE* fp = nullptr;
+  int dir_fd = -1;
+
+  // Build temp config checksum file based on config checksum file (e.g.
+  // bt_config.conf.encrypted-checksum.new).
+  const std::string temp_filename = filename + ".new";
+  base::FilePath path(temp_filename);
+
+  // Extract directory from file path (e.g. /data/misc/bluedroid).
+  const std::string directoryname = base::FilePath(filename).DirName().value();
+  if (directoryname.empty()) {
+    LOG(ERROR) << __func__ << ": error extracting directory from '" << filename
+               << "': " << strerror(errno);
+    goto error2;
+  }
+
+  dir_fd = open(directoryname.c_str(), O_RDONLY);
+  if (dir_fd < 0) {
+    LOG(ERROR) << __func__ << ": unable to open dir '" << directoryname
+               << "': " << strerror(errno);
+    goto error2;
+  }
+
+  if (base::WriteFile(path, checksum.data(), checksum.size()) !=
+      (int)checksum.size()) {
+    LOG(ERROR) << __func__ << ": unable to write file '" << filename.c_str();
+    goto error2;
+  }
+
+  fp = fopen(temp_filename.c_str(), "rb");
+  if (!fp) {
+    LOG(ERROR) << __func__ << ": unable to write to file '" << temp_filename
+               << "': " << strerror(errno);
+    goto error2;
+  }
+
+  // Sync written temp file out to disk. fsync() is blocking until data makes it
+  // to disk.
+  if (fsync(fileno(fp)) < 0) {
+    LOG(WARNING) << __func__ << ": unable to fsync file '" << temp_filename
+                 << "': " << strerror(errno);
+  }
+
+  if (fclose(fp) == EOF) {
+    LOG(ERROR) << __func__ << ": unable to close file '" << temp_filename
+               << "': " << strerror(errno);
+    goto error2;
+  }
+  fp = nullptr;
+
+  // Change the file's permissions to Read/Write by User and Group
+  if (chmod(temp_filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) ==
+      -1) {
+    LOG(ERROR) << __func__ << ": unable to change file permissions '"
+               << filename << "': " << strerror(errno);
+    goto error2;
+  }
+
+  // Rename written temp file to the actual config file.
+  if (rename(temp_filename.c_str(), filename.c_str()) == -1) {
+    LOG(ERROR) << __func__ << ": unable to commit file '" << filename
+               << "': " << strerror(errno);
+    goto error2;
+  }
+
+  // This should ensure the directory is updated as well.
+  if (fsync(dir_fd) < 0) {
+    LOG(WARNING) << __func__ << ": unable to fsync dir '" << directoryname
+                 << "': " << strerror(errno);
+  }
+
+  if (close(dir_fd) < 0) {
+    LOG(ERROR) << __func__ << ": unable to close dir '" << directoryname
+               << "': " << strerror(errno);
+    goto error2;
+  }
+
+  return true;
+
+error2:
+  // This indicates there is a write issue.  Unlink as partial data is not
+  // acceptable.
+  unlink(temp_filename.c_str());
+  if (fp) fclose(fp);
+  if (dir_fd != -1) close(dir_fd);
+  return false;
+}
+
 static char* trim(char* str) {
   while (isspace(*str)) ++str;
 
diff --git a/osi/test/config_test.cc b/osi/test/config_test.cc
index 7c689c9..32858fd 100644
--- a/osi/test/config_test.cc
+++ b/osi/test/config_test.cc
@@ -1,3 +1,4 @@
+#include <base/files/file_util.h>
 #include <gtest/gtest.h>
 
 #include "AllocationTestHarness.h"
@@ -173,3 +174,24 @@
   std::unique_ptr<config_t> config = config_new(CONFIG_FILE);
   EXPECT_TRUE(config_save(*config, CONFIG_FILE));
 }
+
+TEST_F(ConfigTest, checksum_read) {
+  std::string filename = "/data/misc/bluedroid/test.checksum";
+  std::string checksum = "0x1234";
+  base::FilePath file_path(filename);
+
+  EXPECT_EQ(base::WriteFile(file_path, checksum.data(), checksum.size()),
+            (int)checksum.size());
+
+  EXPECT_EQ(checksum_read(filename.c_str()), checksum.c_str());
+}
+
+TEST_F(ConfigTest, checksum_save) {
+  std::string filename = "/data/misc/bluedroid/test.checksum";
+  std::string checksum = "0x1234";
+  base::FilePath file_path(filename);
+
+  EXPECT_TRUE(checksum_save(checksum, filename));
+
+  EXPECT_TRUE(base::PathExists(file_path));
+}
diff --git a/packet/avrcp/general_reject_packet.cc b/packet/avrcp/general_reject_packet.cc
index cde0031..db3d31a 100644
--- a/packet/avrcp/general_reject_packet.cc
+++ b/packet/avrcp/general_reject_packet.cc
@@ -19,11 +19,9 @@
 namespace bluetooth {
 namespace avrcp {
 
-std::unique_ptr<GeneralRejectBuilder> GeneralRejectBuilder::MakeBuilder(
-    BrowsePdu pdu, Status reason) {
+std::unique_ptr<GeneralRejectBuilder> GeneralRejectBuilder::MakeBuilder(Status reason) {
   std::unique_ptr<GeneralRejectBuilder> builder =
-      std::unique_ptr<GeneralRejectBuilder>(
-          new GeneralRejectBuilder(pdu, reason));
+      std::unique_ptr<GeneralRejectBuilder>(new GeneralRejectBuilder(reason));
 
   return builder;
 }
diff --git a/packet/avrcp/general_reject_packet.h b/packet/avrcp/general_reject_packet.h
index 4058fd4..b3fb2fe 100644
--- a/packet/avrcp/general_reject_packet.h
+++ b/packet/avrcp/general_reject_packet.h
@@ -25,8 +25,7 @@
  public:
   virtual ~GeneralRejectBuilder() = default;
 
-  static std::unique_ptr<GeneralRejectBuilder> MakeBuilder(BrowsePdu pdu,
-                                                           Status reason);
+  static std::unique_ptr<GeneralRejectBuilder> MakeBuilder(Status reason);
 
   virtual size_t size() const override;
   virtual bool Serialize(
@@ -35,8 +34,7 @@
  protected:
   Status reason_;
 
-  GeneralRejectBuilder(BrowsePdu pdu, Status reason)
-      : BrowsePacketBuilder(pdu), reason_(reason){};
+  GeneralRejectBuilder(Status reason) : BrowsePacketBuilder(BrowsePdu::GENERAL_REJECT), reason_(reason){};
 };
 
 }  // namespace avrcp
diff --git a/packet/avrcp/register_notification_packet.cc b/packet/avrcp/register_notification_packet.cc
index adb5e59..6bbd16a 100644
--- a/packet/avrcp/register_notification_packet.cc
+++ b/packet/avrcp/register_notification_packet.cc
@@ -39,8 +39,9 @@
 bool RegisterNotificationResponse::IsValid() const {
   if (!VendorPacket::IsValid()) return false;
   if (size() < kMinSize()) return false;
-  if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED)
+  if (GetCType() != CType::INTERIM && GetCType() != CType::CHANGED && GetCType() != CType::REJECTED) {
     return false;
+  }
 
   switch (GetEvent()) {
     case Event::VOLUME_CHANGED:
diff --git a/packet/tests/avrcp/avrcp_test_packets.h b/packet/tests/avrcp/avrcp_test_packets.h
index 13994d0..14e30e7 100644
--- a/packet/tests/avrcp/avrcp_test_packets.h
+++ b/packet/tests/avrcp/avrcp_test_packets.h
@@ -106,8 +106,8 @@
     0x00, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x00};
 
 // AVRCP Register Notification without any parameter
-std::vector<uint8_t> register_notification_invalid = {
-    0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31, 0x00, 0x00, 0x05};
+std::vector<uint8_t> register_notification_invalid = {0x03, 0x48, 0x00, 0x00, 0x19, 0x58, 0x31,
+                                                      0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00};
 
 // AVRCP Interim Playback Status Notification
 std::vector<uint8_t> interim_play_status_notification = {
@@ -208,9 +208,8 @@
 //    start_item = 0x00
 //    end_item = 0x05
 //    attributes_requested: All Items
-std::vector<uint8_t> get_folder_items_request_now_playing = {
-    0x71, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x05, 0x00};
+std::vector<uint8_t> get_folder_items_request_now_playing = {0x71, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00,
+                                                             0x00, 0x00, 0x00, 0x00, 0x05, 0x00};
 
 // AVRCP Browse Get Folder Items Response packet with range out of bounds error
 std::vector<uint8_t> get_folder_items_error_response = {0x71, 0x00, 0x01, 0x0b};
@@ -356,4 +355,36 @@
 std::vector<uint8_t> set_absolute_volume_response = {
     0x09, 0x48, 0x00, 0x00, 0x19, 0x58, 0x50, 0x00, 0x00, 0x01, 0x43};
 
+// Invalid Packets
+// Short Vendor Packet
+std::vector<uint8_t> short_vendor_packet = {0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x01};
+
+// Short Get Capabilities Request Packet
+std::vector<uint8_t> short_get_capabilities_request = {0x01, 0x48, 0x00, 0x00, 0x19, 0x58, 0x10, 0x00, 0x00, 0x00};
+
+// Short Get Element Attributes Request Packet
+std::vector<uint8_t> short_get_element_attributes_request = {0x01, 0x48, 0x00, 0x00, 0x19,
+                                                             0x58, 0x20, 0x00, 0x00, 0x00};
+
+// Short Play Item Request Packet
+std::vector<uint8_t> short_play_item_request = {0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x74, 0x00, 0x00, 0x00};
+
+// Short Set Addressed Player Request Packet
+std::vector<uint8_t> short_set_addressed_player_request = {0x00, 0x48, 0x00, 0x00, 0x19, 0x58, 0x60, 0x00, 0x00, 0x00};
+
+// Short Browse Packet
+std::vector<uint8_t> short_browse_packet = {0x71, 0x00, 0x0a};
+
+// Short Get Folder Items Request Packet
+std::vector<uint8_t> short_get_folder_items_request = {0x71, 0x00, 0x00};
+
+// Short Get Total Number of Items Request Packet
+std::vector<uint8_t> short_get_total_number_of_items_request = {0x75, 0x00, 0x00};
+
+// Short Change Path Request Packet
+std::vector<uint8_t> short_change_path_request = {0x72, 0x00, 0x00};
+
+// Short Get Item Attributes Request Packet
+std::vector<uint8_t> short_get_item_attributes_request = {0x73, 0x00, 0x00};
+
 }  // namespace
diff --git a/packet/tests/avrcp/general_reject_packet_test.cc b/packet/tests/avrcp/general_reject_packet_test.cc
index e27d0b7..4d73dba 100644
--- a/packet/tests/avrcp/general_reject_packet_test.cc
+++ b/packet/tests/avrcp/general_reject_packet_test.cc
@@ -26,8 +26,7 @@
 using TestGeneralRejectPacket = TestPacketType<BrowsePacket>;
 
 TEST(GeneralRejectPacketBuilderTest, buildPacketTest) {
-  auto builder = GeneralRejectBuilder::MakeBuilder(BrowsePdu::GENERAL_REJECT,
-                                                   Status::INVALID_COMMAND);
+  auto builder = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
 
   ASSERT_EQ(builder->size(), general_reject_invalid_command_packet.size());
 
diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp
index d73a5fb..515f513 100644
--- a/profile/avrcp/Android.bp
+++ b/profile/avrcp/Android.bp
@@ -62,3 +62,35 @@
 
     cflags: ["-DBUILDCFG"],
 }
+
+cc_fuzz {
+    name: "avrcp_device_fuzz",
+    host_supported: true,
+    defaults: [
+        "fluoride_defaults_fuzzable",
+    ],
+    srcs: [
+        "tests/avrcp_device_fuzz/avrcp_device_fuzz.cc",
+    ],
+    include_dirs: [
+        "system/bt",
+        "system/bt/packet/tests",
+        "system/bt/btcore/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+    ],
+    static_libs: [
+        "avrcp-target-service",
+        "lib-bt-packets",
+        "libbase",
+        "libchrome",
+        "libcutils",
+        "libevent",
+        "liblog",
+        "libstatslog",
+    ],
+    header_libs: ["libbluetooth_headers"],
+    corpus: [
+        "tests/avrcp_device_fuzz/corpus/*",
+    ],
+}
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
index 3177506..7b2765a 100644
--- a/profile/avrcp/connection_handler.cc
+++ b/profile/avrcp/connection_handler.cc
@@ -138,9 +138,7 @@
 bool ConnectionHandler::DisconnectDevice(const RawAddress& bdaddr) {
   for (auto it = device_map_.begin(); it != device_map_.end(); it++) {
     if (bdaddr == it->second->GetAddress()) {
-      it->second->DeviceDisconnected();
       uint8_t handle = it->first;
-      device_map_.erase(handle);
       return avrc_->Close(handle) == AVRC_SUCCESS;
     }
   }
@@ -536,6 +534,11 @@
   // doesn't need to be processed. In the future, this is the only place sending
   // the packet so none of these layer specific fields will be used.
   pkt->event = 0xFFFF;
+  /* Handle for AVRCP fragment */
+  uint16_t op_code = (uint16_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetOpcode());
+  if (!browse && (op_code == (uint16_t)(Opcode::VENDOR))) {
+    pkt->event = op_code;
+  }
 
   // TODO (apanicke): This layer specific stuff can go away once we move over
   // to the new service.
diff --git a/profile/avrcp/device.cc b/profile/avrcp/device.cc
index cf94cfc..4ca624b 100644
--- a/profile/avrcp/device.cc
+++ b/profile/avrcp/device.cc
@@ -80,6 +80,13 @@
   CHECK(media_interface_);
   DEVICE_VLOG(3) << __func__ << ": pdu=" << pkt->GetCommandPdu();
 
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
   // All CTypes at and above NOT_IMPLEMENTED are all response types.
   if (pkt->GetCType() == CType::NOT_IMPLEMENTED) {
     return;
@@ -125,9 +132,15 @@
     } break;
 
     case CommandPdu::GET_ELEMENT_ATTRIBUTES: {
-      media_interface_->GetSongInfo(base::Bind(
-          &Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
-          label, Packet::Specialize<GetElementAttributesRequest>(pkt)));
+      auto get_element_attributes_request_pkt = Packet::Specialize<GetElementAttributesRequest>(pkt);
+
+      if (!get_element_attributes_request_pkt->IsValid()) {
+        DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+        send_message(label, false, std::move(response));
+      }
+      media_interface_->GetSongInfo(base::Bind(&Device::GetElementAttributesResponse, weak_ptr_factory_.GetWeakPtr(),
+                                               label, get_element_attributes_request_pkt));
     } break;
 
     case CommandPdu::GET_PLAY_STATUS: {
@@ -145,9 +158,17 @@
       // this currently since the current implementation only has one
       // player and the player will never change, but we need it for a
       // more complete implementation.
-      media_interface_->GetMediaPlayerList(base::Bind(
-          &Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
-          label, Packet::Specialize<SetAddressedPlayerRequest>(pkt)));
+      auto set_addressed_player_request = Packet::Specialize<SetAddressedPlayerRequest>(pkt);
+
+      if (!set_addressed_player_request->IsValid()) {
+        DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+        auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+        send_message(label, false, std::move(response));
+        return;
+      }
+
+      media_interface_->GetMediaPlayerList(base::Bind(&Device::HandleSetAddressedPlayer, weak_ptr_factory_.GetWeakPtr(),
+                                                      label, set_addressed_player_request));
     } break;
 
     default: {
@@ -164,6 +185,13 @@
   DEVICE_VLOG(4) << __func__
                  << ": capability=" << pkt->GetCapabilityRequested();
 
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
   switch (pkt->GetCapabilityRequested()) {
     case Capability::COMPANY_ID: {
       auto response =
@@ -202,7 +230,7 @@
 void Device::HandleNotification(
     uint8_t label, const std::shared_ptr<RegisterNotificationRequest>& pkt) {
   if (!pkt->IsValid()) {
-    DEVICE_LOG(ERROR) << __func__ << ": Request packet is not valid";
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
     auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(),
                                                Status::INVALID_PARAMETER);
     send_message(label, false, std::move(response));
@@ -307,6 +335,17 @@
 void Device::HandleVolumeChanged(
     uint8_t label, const std::shared_ptr<RegisterNotificationResponse>& pkt) {
   DEVICE_VLOG(1) << __func__ << ": interim=" << pkt->IsInterim();
+
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+    send_message(label, false, std::move(response));
+    active_labels_.erase(label);
+    volume_interface_ = nullptr;
+    volume_ = VOL_REGISTRATION_FAILED;
+    return;
+  }
+
   if (volume_interface_ == nullptr) return;
 
   if (pkt->GetCType() == CType::REJECTED) {
@@ -546,6 +585,7 @@
     uint8_t label, std::shared_ptr<GetElementAttributesRequest> pkt,
     SongInfo info) {
   DEVICE_VLOG(2) << __func__;
+
   auto get_element_attributes_pkt = pkt;
   auto attributes_requested =
       get_element_attributes_pkt->GetAttributesRequested();
@@ -570,10 +610,15 @@
 }
 
 void Device::MessageReceived(uint8_t label, std::shared_ptr<Packet> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(4) << __func__ << ": opcode=" << pkt->GetOpcode();
-
   active_labels_.insert(label);
-
   switch (pkt->GetOpcode()) {
     // TODO (apanicke): Remove handling of UNIT_INFO and SUBUNIT_INFO from
     // the AVRC_API and instead handle it here to reduce fragmentation.
@@ -583,6 +628,14 @@
     } break;
     case Opcode::PASS_THROUGH: {
       auto pass_through_packet = Packet::Specialize<PassThroughPacket>(pkt);
+
+      if (!pass_through_packet->IsValid()) {
+        DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+        auto response = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+        send_message(label, false, std::move(response));
+        return;
+      }
+
       auto response = PassThroughPacketBuilder::MakeBuilder(
           true, pass_through_packet->GetKeyState() == KeyState::PUSHED,
           pass_through_packet->GetOperationId());
@@ -633,6 +686,13 @@
   DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
                  << " uid=" << pkt->GetUid();
 
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = RejectBuilder::MakeBuilder(pkt->GetCommandPdu(), Status::INVALID_PARAMETER);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
   std::string media_id = "";
   switch (pkt->GetScope()) {
     case Scope::NOW_PLAYING:
@@ -680,6 +740,13 @@
 
 void Device::BrowseMessageReceived(uint8_t label,
                                    std::shared_ptr<BrowsePacket> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
+    send_message(label, false, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(1) << __func__ << ": pdu=" << pkt->GetPdu();
 
   switch (pkt->GetPdu()) {
@@ -704,8 +771,7 @@
       break;
     default:
       DEVICE_LOG(WARNING) << __func__ << ": " << pkt->GetPdu();
-      auto response = GeneralRejectBuilder::MakeBuilder(
-          BrowsePdu::GENERAL_REJECT, Status::INVALID_COMMAND);
+      auto response = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
       send_message(label, true, std::move(response));
 
       break;
@@ -714,6 +780,15 @@
 
 void Device::HandleGetFolderItems(uint8_t label,
                                   std::shared_ptr<GetFolderItemsRequest> pkt) {
+  if (!pkt->IsValid()) {
+    // The specific get folder items builder is unimportant on failure.
+    DEVICE_LOG(WARNING) << __func__ << ": Get folder items request packet is not valid";
+    auto response =
+        GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, browse_mtu_);
+    send_message(label, true, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
 
   switch (pkt->GetScope()) {
@@ -735,12 +810,21 @@
       break;
     default:
       DEVICE_LOG(ERROR) << __func__ << ": " << pkt->GetScope();
+      auto response = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0, browse_mtu_);
+      send_message(label, true, std::move(response));
       break;
   }
 }
 
 void Device::HandleGetTotalNumberOfItems(
     uint8_t label, std::shared_ptr<GetTotalNumberOfItemsRequest> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0);
+    send_message(label, true, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope();
 
   switch (pkt->GetScope()) {
@@ -796,6 +880,13 @@
 
 void Device::HandleChangePath(uint8_t label,
                               std::shared_ptr<ChangePathRequest> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
+    send_message(label, true, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(2) << __func__ << ": direction=" << pkt->GetDirection()
                  << " uid=" << loghex(pkt->GetUid());
 
@@ -846,6 +937,13 @@
 
 void Device::HandleGetItemAttributes(
     uint8_t label, std::shared_ptr<GetItemAttributesRequest> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto builder = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, browse_mtu_);
+    send_message(label, true, std::move(builder));
+    return;
+  }
+
   DEVICE_VLOG(2) << __func__ << ": scope=" << pkt->GetScope()
                  << " uid=" << loghex(pkt->GetUid())
                  << " uid counter=" << loghex(pkt->GetUidCounter());
@@ -856,6 +954,7 @@
     send_message(label, true, std::move(builder));
     return;
   }
+
   switch (pkt->GetScope()) {
     case Scope::NOW_PLAYING: {
       media_interface_->GetNowPlayingList(
@@ -1121,6 +1220,13 @@
 
 void Device::HandleSetBrowsedPlayer(
     uint8_t label, std::shared_ptr<SetBrowsedPlayerRequest> pkt) {
+  if (!pkt->IsValid()) {
+    DEVICE_LOG(WARNING) << __func__ << ": Request packet is not valid";
+    auto response = SetBrowsedPlayerResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0, 0, "");
+    send_message(label, true, std::move(response));
+    return;
+  }
+
   DEVICE_VLOG(2) << __func__ << ": player_id=" << pkt->GetPlayerId();
   media_interface_->SetBrowsedPlayer(
       pkt->GetPlayerId(),
diff --git a/profile/avrcp/tests/avrcp_connection_handler_test.cc b/profile/avrcp/tests/avrcp_connection_handler_test.cc
index 15ea55e..5a811b2 100644
--- a/profile/avrcp/tests/avrcp_connection_handler_test.cc
+++ b/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -56,7 +56,7 @@
         .p_next_attr = nullptr,
         .attr_id = 0,
         .attr_len_type = 0,
-        .attr_value.v.u16 = 0,
+        .attr_value = {.v = {.u16 = 0}},
     };
 
     if (browsing) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_BROWSE;
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
new file mode 100644
index 0000000..24a794d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
@@ -0,0 +1,86 @@
+#include <cstddef>
+#include <cstdint>
+
+#include "avrcp_packet.h"
+#include "device.h"
+#include "packet_test_helper.h"
+#include "stack_config.h"
+
+namespace bluetooth {
+namespace avrcp {
+class FakeMediaInterface : public MediaInterface {
+ public:
+  virtual void SendKeyEvent(uint8_t key, KeyState state) {}
+  using SongInfoCallback = base::Callback<void(SongInfo)>;
+  virtual void GetSongInfo(SongInfoCallback info_cb) {}
+  using PlayStatusCallback = base::Callback<void(PlayStatus)>;
+  virtual void GetPlayStatus(PlayStatusCallback status_cb) {}
+  using NowPlayingCallback =
+      base::Callback<void(std::string, std::vector<SongInfo>)>;
+  virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {}
+  using MediaListCallback =
+      base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
+  virtual void GetMediaPlayerList(MediaListCallback list_cb) {}
+  using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
+  virtual void GetFolderItems(uint16_t player_id, std::string media_id,
+                              FolderItemsCallback folder_cb) {}
+  using SetBrowsedPlayerCallback = base::Callback<void(
+      bool success, std::string root_id, uint32_t num_items)>;
+  virtual void SetBrowsedPlayer(uint16_t player_id,
+                                SetBrowsedPlayerCallback browse_cb) {}
+  virtual void PlayItem(uint16_t player_id, bool now_playing,
+                        std::string media_id) {}
+  virtual void SetActiveDevice(const RawAddress& address) {}
+  virtual void RegisterUpdateCallback(MediaCallbacks* callback) {}
+  virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {}
+};
+
+class FakeVolumeInterface : public VolumeInterface {
+ public:
+  virtual void DeviceConnected(const RawAddress& bdaddr) {}
+  virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {}
+  virtual void DeviceDisconnected(const RawAddress& bdaddr) {}
+  virtual void SetVolume(int8_t volume) {}
+};
+
+class FakeA2dpInterface : public A2dpInterface {
+ public:
+  virtual RawAddress active_peer() { return RawAddress(); }
+  virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) {
+    return false;
+  }
+};
+
+bool get_pts_avrcp_test(void) { return false; }
+
+const stack_config_t interface = {
+    nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr,
+    nullptr};
+
+void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+  FakeMediaInterface fmi;
+  FakeVolumeInterface fvi;
+  FakeA2dpInterface fai;
+
+  std::vector<uint8_t> Packet(Data, Data + Size);
+  Device device(RawAddress::kAny, true,
+                base::Bind([](uint8_t, bool,
+                              std::unique_ptr<::bluetooth::PacketBuilder>) {}),
+                0xFFFF, 0xFFFF);
+  device.RegisterInterfaces(&fmi, &fai, &fvi);
+
+  auto browse_request = TestPacketType<BrowsePacket>::Make(Packet);
+  device.BrowseMessageReceived(1, browse_request);
+
+  auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet);
+  device.MessageReceived(1, avrcp_request);
+  return 0;
+}
+}  // namespace avrcp
+}  // namespace bluetooth
+
+const stack_config_t* stack_config_get_interface(void) {
+  return &bluetooth::avrcp::interface;
+}
\ No newline at end of file
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response
new file mode 100644
index 0000000..f5f982c
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request
new file mode 100644
index 0000000..581327a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response
new file mode 100644
index 0000000..10c7576
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request
new file mode 100644
index 0000000..a222657
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification
new file mode 100644
index 0000000..6ee7661
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification
new file mode 100644
index 0000000..31d50fb
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet
new file mode 100644
index 0000000..83fa427
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request
new file mode 100644
index 0000000..3968c03
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id
new file mode 100644
index 0000000..f3966ed
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown
new file mode 100644
index 0000000..eada547
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id
new file mode 100644
index 0000000..21889ca
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported
new file mode 100644
index 0000000..d2cf8a8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full
new file mode 100644
index 0000000..d79c1d3
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial
new file mode 100644
index 0000000..c37c9b6
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full
new file mode 100644
index 0000000..2e63feb
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response
new file mode 100644
index 0000000..a09361b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response
new file mode 100644
index 0000000..f58889a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response
new file mode 100644
index 0000000..ed25c8c
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request
new file mode 100644
index 0000000..098fa05
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs
new file mode 100644
index 0000000..7e27ff9
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing
new file mode 100644
index 0000000..9eaa355
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title
new file mode 100644
index 0000000..0108fc7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs
new file mode 100644
index 0000000..e8cc867
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response
new file mode 100644
index 0000000..f7472e0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes
new file mode 100644
index 0000000..7d706b8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid
new file mode 100644
index 0000000..d55d0c4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response
new file mode 100644
index 0000000..3553664
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request
new file mode 100644
index 0000000..2311a47
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response
new file mode 100644
index 0000000..240136f
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players
new file mode 100644
index 0000000..a5b85b7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing
new file mode 100644
index 0000000..a4a6654
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs
new file mode 100644
index 0000000..0f9ad75
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response
new file mode 100644
index 0000000..742da96
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification
new file mode 100644
index 0000000..2f6044b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification
new file mode 100644
index 0000000..b643cf4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification
new file mode 100644
index 0000000..ea6675e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification
new file mode 100644
index 0000000..0fb233d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification
new file mode 100644
index 0000000..b23cf6e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton
new file mode 100644
index 0000000..cac9b4a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification
new file mode 100644
index 0000000..101bae6
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed
new file mode 100644
index 0000000..9e002d2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released
new file mode 100644
index 0000000..5c100e8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request
new file mode 100644
index 0000000..538a7c0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response
new file mode 100644
index 0000000..1180bcc
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid
new file mode 100644
index 0000000..2a213f0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification
new file mode 100644
index 0000000..fa40de4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification
new file mode 100644
index 0000000..3e7209b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response
new file mode 100644
index 0000000..82cc047
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification
new file mode 100644
index 0000000..5119a2d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request
new file mode 100644
index 0000000..5403b84
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response
new file mode 100644
index 0000000..b30cde2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request
new file mode 100644
index 0000000..ebe224e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request
new file mode 100644
index 0000000..a38cfb7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response
new file mode 100644
index 0000000..4230524
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request
new file mode 100644
index 0000000..667137b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response
new file mode 100644
index 0000000..c3a3c93
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet
new file mode 100644
index 0000000..b866ef0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request
new file mode 100644
index 0000000..365d337
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request
new file mode 100644
index 0000000..c7c5b33
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request
new file mode 100644
index 0000000..102d788
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request
new file mode 100644
index 0000000..4ab0aa8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request
new file mode 100644
index 0000000..7467555
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request
new file mode 100644
index 0000000..bc634e2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request
new file mode 100644
index 0000000..a138dc4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request
new file mode 100644
index 0000000..4872d6b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet
new file mode 100644
index 0000000..0c2a66e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
index 206e7e2..d221e1b 100644
--- a/profile/avrcp/tests/avrcp_device_test.cc
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -1358,6 +1358,126 @@
   SendMessage(1, reg_notif_request);
 }
 
+TEST_F(AvrcpDeviceTest, invalidVendorPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestAvrcpPacket::Make(short_vendor_packet);
+  SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidCapabilitiesPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestAvrcpPacket::Make(short_get_capabilities_request);
+  SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetElementAttributesPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_ELEMENT_ATTRIBUTES, Status::INVALID_PARAMETER);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestAvrcpPacket::Make(short_get_element_attributes_request);
+  SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidPlayItemPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM, Status::INVALID_PARAMETER);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestAvrcpPacket::Make(short_play_item_request);
+  SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidSetAddressedPlayerPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PARAMETER);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestAvrcpPacket::Make(short_set_addressed_player_request);
+  SendMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidBrowsePacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
+  EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestBrowsePacket::Make(short_browse_packet);
+  SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetFolderItemsPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
+  EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestBrowsePacket::Make(short_get_folder_items_request);
+  SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetTotalNumberOfItemsPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
+  EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestBrowsePacket::Make(short_get_total_number_of_items_request);
+  SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidChangePathPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
+  EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestBrowsePacket::Make(short_change_path_request);
+  SendBrowseMessage(1, short_packet);
+}
+
+TEST_F(AvrcpDeviceTest, invalidGetItemAttributesPacketTest) {
+  MockMediaInterface interface;
+  NiceMock<MockA2dpInterface> a2dp_interface;
+
+  test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
+
+  auto rsp = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0xFFFF);
+  EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
+  auto short_packet = TestBrowsePacket::Make(short_get_item_attributes_request);
+  SendBrowseMessage(1, short_packet);
+}
+
 }  // namespace avrcp
 }  // namespace bluetooth
 
diff --git a/service/adapter.cc b/service/adapter.cc
index 669aeff..4d414dd 100644
--- a/service/adapter.cc
+++ b/service/adapter.cc
@@ -230,7 +230,7 @@
 
   bool IsEnabled() const override { return state_.load() == ADAPTER_STATE_ON; }
 
-  bool Enable(bool start_restricted) override {
+  bool Enable() override {
     AdapterState current_state = GetState();
     if (current_state != ADAPTER_STATE_OFF) {
       LOG(INFO) << "Adapter not disabled - state: "
@@ -243,8 +243,7 @@
     state_ = ADAPTER_STATE_TURNING_ON;
     NotifyAdapterStateChanged(current_state, state_);
 
-    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable(
-        start_restricted);
+    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable();
     if (status != BT_STATUS_SUCCESS) {
       LOG(ERROR) << "Failed to enable Bluetooth - status: "
                  << BtStatusText((const bt_status_t)status);
diff --git a/service/adapter.h b/service/adapter.h
index edb8afe..a4e517c 100644
--- a/service/adapter.h
+++ b/service/adapter.h
@@ -119,10 +119,7 @@
   // to the controller, otherwise returns false. A successful call to this
   // method only means that the enable request has been sent to the Bluetooth
   // controller and does not imply that the operation itself succeeded.
-  // The |start_restricted| flag enables the adapter in restricted mode. In
-  // restricted mode, bonds that are created are marked as restricted in the
-  // config file. These devices are deleted upon leaving restricted mode.
-  virtual bool Enable(bool start_restricted) = 0;
+  virtual bool Enable() = 0;
 
   // Powers off the Bluetooth radio. Returns true, if the disable request was
   // successfully sent to the Bluetooth controller.
diff --git a/service/client/main.cc b/service/client/main.cc
index 43228a4..6458b2d 100644
--- a/service/client/main.cc
+++ b/service/client/main.cc
@@ -389,25 +389,8 @@
 }
 
 void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
-  bool is_restricted_mode = false;
-
-  for (const auto& iter : args) {
-    const std::string& arg = iter;
-    if (arg == "-h") {
-      static const char kUsage[] =
-          "Usage: start-adv [flags]\n"
-          "\n"
-          "Flags:\n"
-          "\t--restricted|-r\tStart in restricted mode\n";
-      cout << kUsage << endl;
-      return;
-    } else if (arg == "--restricted" || arg == "-r") {
-      is_restricted_mode = true;
-    }
-  }
-
   bool status;
-  bt_iface->Enable(is_restricted_mode, &status);
+  bt_iface->Enable(&status);
   PrintCommandStatus(status);
 }
 
diff --git a/service/common/android/bluetooth/IBluetooth.aidl b/service/common/android/bluetooth/IBluetooth.aidl
index 3986ad7..46c7654 100644
--- a/service/common/android/bluetooth/IBluetooth.aidl
+++ b/service/common/android/bluetooth/IBluetooth.aidl
@@ -32,7 +32,7 @@
 interface IBluetooth {
   boolean IsEnabled();
   int GetState();
-  boolean Enable(boolean startRestricted);
+  boolean Enable();
   boolean EnableNoAutoConnect();
   boolean Disable();
 
diff --git a/service/daemon.cc b/service/daemon.cc
index a64c2d8..439c2c2 100644
--- a/service/daemon.cc
+++ b/service/daemon.cc
@@ -59,7 +59,7 @@
   // ipc::IPCManager::Delegate implementation:
   void OnIPCHandlerStarted(ipc::IPCManager::Type /* type */) override {
     if (!settings_->EnableOnStart()) return;
-    adapter_->Enable(false /* start_restricted */);
+    adapter_->Enable();
   }
 
   void OnIPCHandlerStopped(ipc::IPCManager::Type /* type */) override {
diff --git a/service/gatt_server.cc b/service/gatt_server.cc
index 52fd1ed..08c4f83 100644
--- a/service/gatt_server.cc
+++ b/service/gatt_server.cc
@@ -68,18 +68,20 @@
 
   std::vector<btgatt_db_element_t> svc;
 
-  svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
-                                            : BTGATT_DB_SECONDARY_SERVICE),
-                 .uuid = service.uuid()});
+  svc.push_back({
+      .uuid = service.uuid(),
+      .type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
+                                 : BTGATT_DB_SECONDARY_SERVICE),
+  });
 
   for (const auto& characteristic : service.characteristics()) {
-    svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
-                   .uuid = characteristic.uuid(),
+    svc.push_back({.uuid = characteristic.uuid(),
+                   .type = BTGATT_DB_CHARACTERISTIC,
                    .properties = characteristic.properties(),
                    .permissions = characteristic.permissions()});
     for (const auto& descriptor : characteristic.descriptors())
-      svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
-                     .uuid = descriptor.uuid(),
+      svc.push_back({.uuid = descriptor.uuid(),
+                     .type = BTGATT_DB_DESCRIPTOR,
                      .permissions = descriptor.permissions()});
   }
 
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index b583d93..cfc394c 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -136,8 +136,10 @@
 
   g_internal->server_if = server_if;
 
-  pending_svc_decl.push_back(
-      {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = app_uuid});
+  pending_svc_decl.push_back({
+      .uuid = app_uuid,
+      .type = BTGATT_DB_PRIMARY_SERVICE,
+  });
 }
 
 void ServiceAddedCallback(int status, int server_if,
@@ -502,8 +504,8 @@
 bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid,
                                                uint8_t properties,
                                                uint16_t permissions) {
-  pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC,
-                              .uuid = uuid,
+  pending_svc_decl.push_back({.uuid = uuid,
+                              .type = BTGATT_DB_CHARACTERISTIC,
                               .properties = properties,
                               .permissions = permissions});
   return BT_STATUS_SUCCESS;
diff --git a/service/hal/bluetooth_interface.cc b/service/hal/bluetooth_interface.cc
index a08fb7b..5ca220c 100644
--- a/service/hal/bluetooth_interface.cc
+++ b/service/hal/bluetooth_interface.cc
@@ -254,7 +254,7 @@
 
     // Initialize the Bluetooth interface. Set up the adapter (Bluetooth DM) API
     // callbacks.
-    status = hal_iface_->init(&bt_callbacks);
+    status = hal_iface_->init(&bt_callbacks, false, false);
     if (status != BT_STATUS_SUCCESS) {
       LOG(ERROR) << "Failed to initialize Bluetooth stack";
       return false;
diff --git a/service/hal/fake_bluetooth_interface.cc b/service/hal/fake_bluetooth_interface.cc
index 7979155..f1d03ad 100644
--- a/service/hal/fake_bluetooth_interface.cc
+++ b/service/hal/fake_bluetooth_interface.cc
@@ -23,7 +23,7 @@
 
 FakeBluetoothInterface::Manager g_hal_manager;
 
-int FakeHALEnable(bool start_restricted) {
+int FakeHALEnable() {
   return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
diff --git a/service/ipc/binder/bluetooth_binder_server.cc b/service/ipc/binder/bluetooth_binder_server.cc
index ca36019..097abb7 100644
--- a/service/ipc/binder/bluetooth_binder_server.cc
+++ b/service/ipc/binder/bluetooth_binder_server.cc
@@ -64,10 +64,9 @@
   return Status::ok();
 }
 
-Status BluetoothBinderServer::Enable(bool start_restricted,
-                                     bool* _aidl_return) {
+Status BluetoothBinderServer::Enable(bool* _aidl_return) {
   VLOG(2) << __func__;
-  *_aidl_return = adapter_->Enable(start_restricted);
+  *_aidl_return = adapter_->Enable();
   return Status::ok();
 }
 
diff --git a/service/ipc/binder/bluetooth_binder_server.h b/service/ipc/binder/bluetooth_binder_server.h
index bfeb589..7131e8b 100644
--- a/service/ipc/binder/bluetooth_binder_server.h
+++ b/service/ipc/binder/bluetooth_binder_server.h
@@ -71,7 +71,7 @@
   // IBluetooth overrides:
   Status IsEnabled(bool* _aidl_return) override;
   Status GetState(int32_t* _aidl_return) override;
-  Status Enable(bool start_restricted, bool* _aidl_return) override;
+  Status Enable(bool* _aidl_return) override;
   Status EnableNoAutoConnect(bool* _aidl_return) override;
   Status Disable(bool* _aidl_return) override;
 
diff --git a/service/low_energy_client.cc b/service/low_energy_client.cc
index cc127c3..cb8bcf1 100644
--- a/service/low_energy_client.cc
+++ b/service/low_energy_client.cc
@@ -188,8 +188,8 @@
 
   if (!bda) return;
 
-  const char* addr = BtAddrString(bda).c_str();
-  if (delegate_) delegate_->OnMtuChanged(this, status, addr, mtu);
+  std::string addr = BtAddrString(bda);
+  if (delegate_) delegate_->OnMtuChanged(this, status, addr.c_str(), mtu);
 }
 
 // LowEnergyClientFactory implementation
diff --git a/service/test/adapter_unittest.cc b/service/test/adapter_unittest.cc
index e6f5d10..b1cedc1 100644
--- a/service/test/adapter_unittest.cc
+++ b/service/test/adapter_unittest.cc
@@ -124,12 +124,12 @@
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
 
   // Enable fails at HAL level
-  EXPECT_FALSE(adapter_->Enable(false));
+  EXPECT_FALSE(adapter_->Enable());
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
 
   // Enable success
   fake_hal_manager_->enable_succeed = true;
-  EXPECT_TRUE(adapter_->Enable(false));
+  EXPECT_TRUE(adapter_->Enable());
 
   // Should have received a state update.
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
@@ -137,7 +137,7 @@
 
   // Enable fails because not disabled
   EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, adapter_->GetState());
-  EXPECT_FALSE(adapter_->Enable(false));
+  EXPECT_FALSE(adapter_->Enable());
 
   // Adapter state updates properly
   fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
@@ -148,7 +148,7 @@
   EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
 
   // Enable fails because already enabled
-  EXPECT_FALSE(adapter_->Enable(false));
+  EXPECT_FALSE(adapter_->Enable());
 }
 
 TEST_F(AdapterTest, Disable) {
diff --git a/service/test/gatt_server_unittest.cc b/service/test/gatt_server_unittest.cc
index 7d7fec2..e19742d 100644
--- a/service/test/gatt_server_unittest.cc
+++ b/service/test/gatt_server_unittest.cc
@@ -267,14 +267,14 @@
     desc_handle_ = 0x0004;
 
     std::vector<btgatt_db_element_t> service_with_handles = {
-        {.type = BTGATT_DB_PRIMARY_SERVICE,
-         .uuid = uuid0,
+        {.uuid = uuid0,
+         .type = BTGATT_DB_PRIMARY_SERVICE,
          .attribute_handle = srvc_handle_},
-        {.type = BTGATT_DB_CHARACTERISTIC,
-         .uuid = uuid1,
+        {.uuid = uuid1,
+         .type = BTGATT_DB_CHARACTERISTIC,
          .attribute_handle = char_handle_},
-        {.type = BTGATT_DB_DESCRIPTOR,
-         .uuid = uuid2,
+        {.uuid = uuid2,
+         .type = BTGATT_DB_DESCRIPTOR,
          .attribute_handle = desc_handle_},
     };
 
diff --git a/service/test/mock_adapter.h b/service/test/mock_adapter.h
index 2c496b1..b652026 100644
--- a/service/test/mock_adapter.h
+++ b/service/test/mock_adapter.h
@@ -32,7 +32,7 @@
   MOCK_METHOD1(RemoveObserver, void(Observer*));
   MOCK_CONST_METHOD0(GetState, AdapterState());
   MOCK_CONST_METHOD0(IsEnabled, bool());
-  MOCK_METHOD1(Enable, bool(bool));
+  MOCK_METHOD0(Enable, bool());
   MOCK_METHOD0(Disable, bool());
   MOCK_CONST_METHOD0(GetName, std::string());
   MOCK_METHOD1(SetName, bool(const std::string&));
diff --git a/stack/Android.bp b/stack/Android.bp
index 03f93a5..b573aaf 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -46,7 +46,6 @@
         "system/bt/bta/sys",
         "system/bt/utils/include",
     ],
-    cflags: ["-Wno-implicit-fallthrough"],
     srcs: crypto_toolbox_srcs + [
         "a2dp/a2dp_aac.cc",
         "a2dp/a2dp_aac_decoder.cc",
@@ -178,7 +177,6 @@
     shared_libs: [
         "libcutils",
         "liblog",
-        "libstatslog",
     ],
     required: [
         "libldacBT_enc",
@@ -204,6 +202,7 @@
     ],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "android.hardware.bluetooth.a2dp@1.0",
         "android.hardware.bluetooth.audio@2.0",
         "libaudioclient",
@@ -211,8 +210,6 @@
         "libdl",
         "libfmq",
         "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
         "liblog",
         "libprocessgroup",
         "libprotobuf-cpp-lite",
@@ -281,6 +278,7 @@
         "rfcomm/rfc_ts_frames.cc",
         "rfcomm/rfc_utils.cc",
         "test/common/mock_btm_layer.cc",
+        "test/common/mock_btsnoop_module.cc",
         "test/common/mock_btu_layer.cc",
         "test/common/mock_l2cap_layer.cc",
         "test/common/stack_test_packet_utils.cc",
diff --git a/stack/a2dp/a2dp_vendor_aptx_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
index e7d0145..0d605c0 100644
--- a/stack/a2dp/a2dp_vendor_aptx_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_encoder.cc
@@ -26,7 +26,6 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx.h"
 #include "bt_common.h"
-#include "common/scoped_scs_exit.h"
 #include "common/time_util.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -55,25 +54,6 @@
 static tAPTX_ENCODER_ENCODE_STEREO aptx_encoder_encode_stereo_func;
 static tAPTX_ENCODER_SIZEOF_PARAMS aptx_encoder_sizeof_params_func;
 
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_encoder_init(void* state, short endian) {
-  ScopedSCSExit x;
-  return aptx_encoder_init_func(state, endian);
-}
-
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
-                                      void* buffer) {
-  ScopedSCSExit x;
-  return aptx_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
-}
-
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_encoder_sizeof_params() {
-  ScopedSCSExit x;
-  return aptx_encoder_sizeof_params_func();
-}
-
 // offset
 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
 #define A2DP_APTX_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -212,9 +192,9 @@
 #endif
 
   a2dp_aptx_encoder_cb.aptx_encoder_state =
-      osi_malloc(aptx_encoder_sizeof_params());
+      osi_malloc(aptx_encoder_sizeof_params_func());
   if (a2dp_aptx_encoder_cb.aptx_encoder_state != NULL) {
-    aptx_encoder_init(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
+    aptx_encoder_init_func(a2dp_aptx_encoder_cb.aptx_encoder_state, 0);
   } else {
     LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX encoder state", __func__);
     // TODO: Return an error?
@@ -486,8 +466,8 @@
       pcmR[i] = (uint16_t) * (data16_in + ((2 * j) + 1));
     }
 
-    aptx_encoder_encode_stereo(a2dp_aptx_encoder_cb.aptx_encoder_state, &pcmL,
-                               &pcmR, &encoded_sample);
+    aptx_encoder_encode_stereo_func(a2dp_aptx_encoder_cb.aptx_encoder_state,
+                                    &pcmL, &pcmR, &encoded_sample);
 
     data_out[*data_out_index + 0] = (uint8_t)((encoded_sample[0] >> 8) & 0xff);
     data_out[*data_out_index + 1] = (uint8_t)((encoded_sample[0] >> 0) & 0xff);
diff --git a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
index d271e0d..fb782dd 100644
--- a/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
+++ b/stack/a2dp/a2dp_vendor_aptx_hd_encoder.cc
@@ -26,7 +26,6 @@
 #include "a2dp_vendor.h"
 #include "a2dp_vendor_aptx_hd.h"
 #include "bt_common.h"
-#include "common/scoped_scs_exit.h"
 #include "common/time_util.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
@@ -56,25 +55,6 @@
 static tAPTX_HD_ENCODER_ENCODE_STEREO aptx_hd_encoder_encode_stereo_func;
 static tAPTX_HD_ENCODER_SIZEOF_PARAMS aptx_hd_encoder_sizeof_params_func;
 
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_hd_encoder_init(void* state, short endian) {
-  ScopedSCSExit x;
-  return aptx_hd_encoder_init_func(state, endian);
-}
-
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_hd_encoder_encode_stereo(void* state, void* pcmL, void* pcmR,
-                                         void* buffer) {
-  ScopedSCSExit x;
-  return aptx_hd_encoder_encode_stereo_func(state, pcmL, pcmR, buffer);
-}
-
-__attribute__((no_sanitize("shadow-call-stack")))
-static int aptx_hd_encoder_sizeof_params() {
-  ScopedSCSExit x;
-  return aptx_hd_encoder_sizeof_params_func();
-}
-
 // offset
 #if (BTA_AV_CO_CP_SCMS_T == TRUE)
 #define A2DP_APTX_HD_OFFSET (AVDT_MEDIA_OFFSET + 1)
@@ -213,9 +193,9 @@
 #endif
 
   a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state =
-      osi_malloc(aptx_hd_encoder_sizeof_params());
+      osi_malloc(aptx_hd_encoder_sizeof_params_func());
   if (a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state != NULL) {
-    aptx_hd_encoder_init(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
+    aptx_hd_encoder_init_func(a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, 0);
   } else {
     LOG_ERROR(LOG_TAG, "%s: Cannot allocate aptX-HD encoder state", __func__);
     // TODO: Return an error?
@@ -480,7 +460,7 @@
       p += 3;
     }
 
-    aptx_hd_encoder_encode_stereo(
+    aptx_hd_encoder_encode_stereo_func(
         a2dp_aptx_hd_encoder_cb.aptx_hd_encoder_state, &pcmL, &pcmR,
         &encoded_sample);
 
diff --git a/stack/avct/avct_api.cc b/stack/avct/avct_api.cc
index 5ced71f..51e2daf 100644
--- a/stack/avct/avct_api.cc
+++ b/stack/avct/avct_api.cc
@@ -56,7 +56,8 @@
   AVCT_TRACE_API("AVCT_Register");
 
   /* register PSM with L2CAP */
-  L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_appl);
+  L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_appl,
+                true /* enable_snoop */);
 
   /* set security level */
   BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0,
@@ -68,7 +69,8 @@
   memset(&avct_cb, 0, sizeof(tAVCT_CB));
 
   /* Include the browsing channel which uses eFCR */
-  L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_br_appl);
+  L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_br_appl,
+                true /*enable_snoop*/);
 
   /* AVCTP browsing channel uses the same security service as AVCTP control
    * channel */
diff --git a/stack/avct/avct_lcb_act.cc b/stack/avct/avct_lcb_act.cc
index faa098b..eec049d 100644
--- a/stack/avct/avct_lcb_act.cc
+++ b/stack/avct/avct_lcb_act.cc
@@ -53,6 +53,12 @@
   uint8_t pkt_type;
   BT_HDR* p_ret;
 
+  if (p_buf->len < 1) {
+    osi_free(p_buf);
+    p_ret = NULL;
+    return p_ret;
+  }
+
   /* parse the message header */
   p = (uint8_t*)(p_buf + 1) + p_buf->offset;
   pkt_type = AVCT_PKT_TYPE(p);
diff --git a/stack/avdt/avdt_api.cc b/stack/avdt/avdt_api.cc
index 903862e..9350c31 100644
--- a/stack/avdt/avdt_api.cc
+++ b/stack/avdt/avdt_api.cc
@@ -90,7 +90,8 @@
  ******************************************************************************/
 void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
   /* register PSM with L2CAP */
-  L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl);
+  L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl,
+                true /* enable_snoop */);
 
   /* set security level */
   BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
diff --git a/stack/avdt/avdt_msg.cc b/stack/avdt/avdt_msg.cc
index 0ac9b64..853f369 100644
--- a/stack/avdt/avdt_msg.cc
+++ b/stack/avdt/avdt_msg.cc
@@ -586,6 +586,10 @@
     /* parse individual information elements with additional parameters */
     switch (elem) {
       case AVDT_CAT_RECOV:
+        if ((p_end - p) < 3) {
+          err = AVDT_ERR_PAYLOAD;
+          break;
+        }
         p_cfg->recov_type = *p++;
         p_cfg->recov_mrws = *p++;
         p_cfg->recov_mnmp = *p++;
@@ -617,6 +621,10 @@
         break;
 
       case AVDT_CAT_HDRCMP:
+        if ((p_end - p) < 1) {
+          err = AVDT_ERR_PAYLOAD;
+          break;
+        }
         p_cfg->hdrcmp_mask = *p++;
         break;
 
@@ -1191,6 +1199,14 @@
 
   /* parse the message header */
   p = (uint8_t*)(p_buf + 1) + p_buf->offset;
+
+  /* Check if is valid length */
+  if (p_buf->len < 1) {
+    android_errorWriteLog(0x534e4554, "78287084");
+    osi_free(p_buf);
+    p_ret = NULL;
+    return p_ret;
+  }
   AVDT_MSG_PRS_PKT_TYPE(p, pkt_type);
 
   /* quick sanity check on length */
@@ -1499,8 +1515,8 @@
   uint8_t pkt_type;
   uint8_t msg_type;
   uint8_t sig = 0;
-  tAVDT_MSG msg;
-  AvdtpSepConfig cfg;
+  tAVDT_MSG msg{};
+  AvdtpSepConfig cfg{};
   uint8_t err;
   uint8_t evt = 0;
   uint8_t scb_hdl;
diff --git a/stack/avrc/avrc_api.cc b/stack/avrc/avrc_api.cc
index e2f109a..62b7fe4 100644
--- a/stack/avrc/avrc_api.cc
+++ b/stack/avrc/avrc_api.cc
@@ -32,6 +32,7 @@
 #include "btu.h"
 #include "osi/include/fixed_queue.h"
 #include "osi/include/osi.h"
+#include "osi/include/properties.h"
 
 /*****************************************************************************
  *  Global data
@@ -1113,27 +1114,32 @@
 
   AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d", __func__,
                    handle, label, ctype, p_pkt->len);
-
+  /* Handle for AVRCP fragment */
+  bool is_new_avrcp = osi_property_get_bool("persist.bluetooth.enablenewavrcp", true);
   if (ctype >= AVRC_RSP_NOT_IMPL) cr = AVCT_RSP;
 
   if (p_pkt->event == AVRC_OP_VENDOR) {
-    /* add AVRCP Vendor Dependent headers */
-    p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
-    p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
-    p_pkt->len += AVRC_VENDOR_HDR_SIZE;
-    p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
-    *p_data++ = (ctype & AVRC_CTYPE_MASK);
-    *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
-    *p_data++ = AVRC_OP_VENDOR;
-    AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+    if (is_new_avrcp) {
+      p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset + AVRC_VENDOR_HDR_SIZE;
+    } else {
+      /* add AVRCP Vendor Dependent headers */
+      p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+      p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
+      p_pkt->len += AVRC_VENDOR_HDR_SIZE;
+      p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+      *p_data++ = (ctype & AVRC_CTYPE_MASK);
+      *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+      *p_data++ = AVRC_OP_VENDOR;
+      AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
 
-    /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
-    if (cr == AVCT_CMD) {
-      msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
+      /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
+      if (cr == AVCT_CMD) {
+        msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
 
-      if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP) ||
-          (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP)) {
-        msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+        if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP) ||
+            (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP)) {
+          msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+        }
       }
     }
   } else if (p_pkt->event == AVRC_OP_PASS_THRU) {
diff --git a/stack/avrc/avrc_bld_tg.cc b/stack/avrc/avrc_bld_tg.cc
index b28c9e2..1dac160 100644
--- a/stack/avrc/avrc_bld_tg.cc
+++ b/stack/avrc/avrc_bld_tg.cc
@@ -1338,8 +1338,7 @@
     case AVRC_OP_VENDOR:
       /* reserved 0, packet_type 0 */
       UINT8_TO_BE_STREAM(p_data, 0);
-    /* continue to the next "case to add length */
-
+      [[fallthrough]];
     case AVRC_OP_BROWSE:
       /* add fixed lenth - 0 */
       UINT16_TO_BE_STREAM(p_data, 0);
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index 80dc882..39ed921 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -806,7 +806,7 @@
       if (len < min_len) goto length_error;
       BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
       BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
-      BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+      BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p);
       break;
 
     case AVRC_PDU_SET_ADDRESSED_PLAYER:
diff --git a/stack/avrc/avrc_pars_tg.cc b/stack/avrc/avrc_pars_tg.cc
index c0504ee..22471bd 100644
--- a/stack/avrc/avrc_pars_tg.cc
+++ b/stack/avrc/avrc_pars_tg.cc
@@ -135,15 +135,16 @@
       if (!AVRC_IS_VALID_CAP_ID(p_result->get_caps.capability_id))
         status = AVRC_STS_BAD_PARAM;
       else if (len != 1)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       break;
 
     case AVRC_PDU_LIST_PLAYER_APP_ATTR: /* 0x11 */
       /* no additional parameters */
-      if (len != 0) status = AVRC_STS_INTERNAL_ERR;
+      if (len != 0) return AVRC_STS_INTERNAL_ERR;
       break;
 
     case AVRC_PDU_LIST_PLAYER_APP_VALUES: /* 0x12 */
+      if (len == 0) return AVRC_STS_INTERNAL_ERR;
       p_result->list_app_values.attr_id = *p++;
       if (!AVRC_IS_VALID_ATTRIBUTE(p_result->list_app_values.attr_id))
         status = AVRC_STS_BAD_PARAM;
@@ -153,6 +154,7 @@
 
     case AVRC_PDU_GET_CUR_PLAYER_APP_VALUE: /* 0x13 */
     case AVRC_PDU_GET_PLAYER_APP_ATTR_TEXT: /* 0x15 */
+      if (len == 0) return AVRC_STS_INTERNAL_ERR;
       BE_STREAM_TO_UINT8(p_result->get_cur_app_val.num_attr, p);
       if (len != (p_result->get_cur_app_val.num_attr + 1)) {
         status = AVRC_STS_INTERNAL_ERR;
@@ -177,6 +179,7 @@
       break;
 
     case AVRC_PDU_SET_PLAYER_APP_VALUE: /* 0x14 */
+      if (len == 0) return AVRC_STS_INTERNAL_ERR;
       BE_STREAM_TO_UINT8(p_result->set_app_val.num_val, p);
       size_needed = sizeof(tAVRC_APP_SETTING);
       if (p_buf && (len == ((p_result->set_app_val.num_val << 1) + 1))) {
@@ -208,7 +211,7 @@
 
     case AVRC_PDU_GET_PLAYER_APP_VALUE_TEXT: /* 0x16 */
       if (len < 3)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else {
         BE_STREAM_TO_UINT8(p_result->get_app_val_txt.attr_id, p);
         if (!AVRC_IS_VALID_ATTRIBUTE(p_result->get_app_val_txt.attr_id))
@@ -240,7 +243,7 @@
 
     case AVRC_PDU_INFORM_DISPLAY_CHARSET: /* 0x17 */
       if (len < 3)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else {
         BE_STREAM_TO_UINT8(p_result->inform_charset.num_id, p);
         if ((len - 1 /* num_id */) != p_result->inform_charset.num_id * 2)
@@ -258,7 +261,7 @@
 
     case AVRC_PDU_INFORM_BATTERY_STAT_OF_CT: /* 0x18 */
       if (len != 1)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else {
         p_result->inform_battery_status.battery_status = *p++;
         if (!AVRC_IS_VALID_BATTERY_STATUS(
@@ -269,7 +272,7 @@
 
     case AVRC_PDU_GET_ELEMENT_ATTR: /* 0x20 */
       if (len < 9)                  /* UID/8 and num_attr/1 */
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else {
         BE_STREAM_TO_UINT32(u32, p);
         BE_STREAM_TO_UINT32(u32_2, p);
@@ -293,12 +296,12 @@
 
     case AVRC_PDU_GET_PLAY_STATUS: /* 0x30 */
       /* no additional parameters */
-      if (len != 0) status = AVRC_STS_INTERNAL_ERR;
+      if (len != 0) return AVRC_STS_INTERNAL_ERR;
       break;
 
     case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */
       if (len != 5)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else {
         BE_STREAM_TO_UINT8(p_result->reg_notif.event_id, p);
         BE_STREAM_TO_UINT32(p_result->reg_notif.param, p);
@@ -307,21 +310,21 @@
 
     case AVRC_PDU_SET_ABSOLUTE_VOLUME: /* 0x50 */
       if (len != 1)
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       else
         p_result->volume.volume = *p++;
       break;
 
     case AVRC_PDU_REQUEST_CONTINUATION_RSP: /* 0x40 */
       if (len != 1) {
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       }
       BE_STREAM_TO_UINT8(p_result->continu.target_pdu, p);
       break;
 
     case AVRC_PDU_ABORT_CONTINUATION_RSP: /* 0x41 */
       if (len != 1) {
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       }
       BE_STREAM_TO_UINT8(p_result->abort.target_pdu, p);
       break;
@@ -330,14 +333,14 @@
       if (len != 2) {
         AVRC_TRACE_ERROR("AVRC_PDU_SET_ADDRESSED_PLAYER length is incorrect:%d",
                          len);
-        status = AVRC_STS_INTERNAL_ERR;
+        return AVRC_STS_INTERNAL_ERR;
       }
       BE_STREAM_TO_UINT16(p_result->addr_player.player_id, p);
       break;
 
     case AVRC_PDU_PLAY_ITEM:          /* 0x74 */
     case AVRC_PDU_ADD_TO_NOW_PLAYING: /* 0x90 */
-      if (len != (AVRC_UID_SIZE + 3)) status = AVRC_STS_INTERNAL_ERR;
+      if (len != (AVRC_UID_SIZE + 3)) return AVRC_STS_INTERNAL_ERR;
       BE_STREAM_TO_UINT8(p_result->play_item.scope, p);
       if (p_result->play_item.scope > AVRC_SCOPE_NOW_PLAYING) {
         status = AVRC_STS_BAD_SCOPE;
diff --git a/stack/bnep/bnep_api.cc b/stack/bnep/bnep_api.cc
index 0e7b692..809d0b2 100644
--- a/stack/bnep/bnep_api.cc
+++ b/stack/bnep/bnep_api.cc
@@ -340,7 +340,7 @@
   p_bcb = &(bnep_cb.bcb[handle - 1]);
   /* Check MTU size */
   if (p_buf->len > BNEP_MTU_SIZE) {
-    BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", p_buf->len,
+    BNEP_TRACE_ERROR("%s length %d exceeded MTU %d", __func__, p_buf->len,
                      BNEP_MTU_SIZE);
     osi_free(p_buf);
     return (BNEP_MTU_EXCEDED);
@@ -349,7 +349,7 @@
   /* Check if the packet should be filtered out */
   p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;
   if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
-                             p_data) != BNEP_SUCCESS) {
+                             p_data, p_buf->len) != BNEP_SUCCESS) {
     /*
     ** If packet is filtered and ext headers are present
     ** drop the data and forward the ext headers
@@ -361,6 +361,11 @@
       org_len = p_buf->len;
       new_len = 0;
       do {
+        if ((new_len + 2) > org_len) {
+          osi_free(p_buf);
+          return BNEP_IGNORE_CMD;
+        }
+
         ext = *p_data++;
         length = *p_data++;
         p_data += length;
@@ -437,7 +442,7 @@
 
   /* Check MTU size. Consider the possibility of having extension headers */
   if (len > BNEP_MTU_SIZE) {
-    BNEP_TRACE_ERROR("BNEP_Write() length %d exceeded MTU %d", len,
+    BNEP_TRACE_ERROR("%s length %d exceeded MTU %d", __func__, len,
                      BNEP_MTU_SIZE);
     return (BNEP_MTU_EXCEDED);
   }
@@ -448,7 +453,7 @@
 
   /* Check if the packet should be filtered out */
   if (bnep_is_packet_allowed(p_bcb, p_dest_addr, protocol, fw_ext_present,
-                             p_data) != BNEP_SUCCESS) {
+                             p_data, len) != BNEP_SUCCESS) {
     /*
     ** If packet is filtered and ext headers are present
     ** drop the data and forward the ext headers
@@ -461,6 +466,10 @@
       new_len = 0;
       p = p_data;
       do {
+        if ((new_len + 2) > org_len) {
+          return BNEP_IGNORE_CMD;
+        }
+
         ext = *p_data++;
         length = *p_data++;
         p_data += length;
diff --git a/stack/bnep/bnep_int.h b/stack/bnep/bnep_int.h
index 2587147..5bba15d 100644
--- a/stack/bnep/bnep_int.h
+++ b/stack/bnep/bnep_int.h
@@ -229,7 +229,7 @@
 extern tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb,
                                            const RawAddress& p_dest_addr,
                                            uint16_t protocol,
-                                           bool fw_ext_present,
-                                           uint8_t* p_data);
+                                           bool fw_ext_present, uint8_t* p_data,
+                                           uint16_t org_len);
 
 #endif
diff --git a/stack/bnep/bnep_main.cc b/stack/bnep/bnep_main.cc
index ae6c51b..265ec79 100644
--- a/stack/bnep/bnep_main.cc
+++ b/stack/bnep/bnep_main.cc
@@ -94,7 +94,8 @@
   bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(BT_PSM_BNEP, &bnep_cb.reg_info)) {
+  if (!L2CA_Register(BT_PSM_BNEP, &bnep_cb.reg_info,
+                     false /* enable_snoop */)) {
     BNEP_TRACE_ERROR("BNEP - Registration failed");
     return BNEP_SECURITY_FAIL;
   }
diff --git a/stack/bnep/bnep_utils.cc b/stack/bnep/bnep_utils.cc
index 6d6d709..ac74ce0 100644
--- a/stack/bnep/bnep_utils.cc
+++ b/stack/bnep/bnep_utils.cc
@@ -1259,23 +1259,33 @@
 tBNEP_RESULT bnep_is_packet_allowed(tBNEP_CONN* p_bcb,
                                     const RawAddress& p_dest_addr,
                                     uint16_t protocol, bool fw_ext_present,
-                                    uint8_t* p_data) {
+                                    uint8_t* p_data, uint16_t org_len) {
   if (p_bcb->rcvd_num_filters) {
     uint16_t i, proto;
 
     /* Findout the actual protocol to check for the filtering */
     proto = protocol;
     if (proto == BNEP_802_1_P_PROTOCOL) {
+      uint16_t new_len = 0;
       if (fw_ext_present) {
         uint8_t len, ext;
         /* parse the extension headers and findout actual protocol */
         do {
+          if ((new_len + 2) > org_len) {
+            return BNEP_IGNORE_CMD;
+          }
+
           ext = *p_data++;
           len = *p_data++;
           p_data += len;
 
+          new_len += (len + 2);
+
         } while (ext & 0x80);
       }
+      if ((new_len + 4) > org_len) {
+        return BNEP_IGNORE_CMD;
+      }
       p_data += 2;
       BE_STREAM_TO_UINT16(proto, p_data);
     }
diff --git a/stack/btm/ble_advertiser_hci_interface.cc b/stack/btm/ble_advertiser_hci_interface.cc
index dddf8d4..fbf8d27 100644
--- a/stack/btm/ble_advertiser_hci_interface.cc
+++ b/stack/btm/ble_advertiser_hci_interface.cc
@@ -97,7 +97,7 @@
 class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
   void SendAdvCmd(const base::Location& posted_from, uint8_t param_len,
                   uint8_t* param_buf, status_cb command_complete) {
-    btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV_OCF, param_buf,
+    btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV, param_buf,
                               param_len,
                               base::Bind(&btm_ble_multi_adv_vsc_cmpl_cback,
                                          param_buf[0], command_complete));
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index dcb2fb4..2a417b9 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -825,7 +825,8 @@
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_or_alloc_dev(bda);
 
   /* If there are any preferred connection parameters, set them now */
-  if ((p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
+  if ((p_lcb != NULL) && (p_dev_rec != NULL) &&
+      (p_dev_rec->conn_params.min_conn_int >= BTM_BLE_CONN_INT_MIN) &&
       (p_dev_rec->conn_params.min_conn_int <= BTM_BLE_CONN_INT_MAX) &&
       (p_dev_rec->conn_params.max_conn_int >= BTM_BLE_CONN_INT_MIN) &&
       (p_dev_rec->conn_params.max_conn_int <= BTM_BLE_CONN_INT_MAX) &&
@@ -2607,7 +2608,7 @@
   } else {
     if (!BTM_ACL_IS_CONNECTED(bda)) {
       VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
-      if (btm_cb.paging && bda != btm_cb.connecting_bda) {
+      if (btm_cb.paging && bda == btm_cb.connecting_bda) {
         fixed_queue_enqueue(btm_cb.page_queue, p);
       } else {
         p_dev_rec = btm_find_or_alloc_dev(bda);
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 77604ee..1c4aa37 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -39,8 +39,10 @@
 #include "gap_api.h"
 #include "gatt_api.h"
 #include "hcimsgs.h"
-#include "log/log.h"
 #include "l2c_int.h"
+#include "log/log.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/shim.h"
 #include "osi/include/log.h"
 #include "osi/include/osi.h"
 #include "stack/crypto_toolbox/crypto_toolbox.h"
@@ -69,6 +71,11 @@
  ******************************************************************************/
 bool BTM_SecAddBleDevice(const RawAddress& bd_addr, BD_NAME bd_name,
                          tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SecAddBleDevice(bd_addr, bd_name, dev_type,
+                                                addr_type);
+  }
+
   BTM_TRACE_DEBUG("%s: dev_type=0x%x", __func__, dev_type);
 
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
@@ -130,6 +137,10 @@
  ******************************************************************************/
 bool BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
                       tBTM_LE_KEY_TYPE key_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SecAddBleKey(bd_addr, p_le_key, key_type);
+  }
+
   tBTM_SEC_DEV_REC* p_dev_rec;
   BTM_TRACE_DEBUG("BTM_SecAddBleKey");
   p_dev_rec = btm_find_dev(bd_addr);
@@ -170,6 +181,10 @@
  *
  ******************************************************************************/
 void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleLoadLocalKeys(key_type, p_key);
+  }
+
   tBTM_DEVCB* p_devcb = &btm_cb.devcb;
   BTM_TRACE_DEBUG("%s", __func__);
   if (p_key != NULL) {
@@ -192,14 +207,27 @@
 
 /** Returns local device encryption root (ER) */
 const Octet16& BTM_GetDeviceEncRoot() {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_GetDeviceEncRoot();
+  }
   return btm_cb.devcb.ble_encryption_key_value;
 }
 
 /** Returns local device identity root (IR). */
-const Octet16& BTM_GetDeviceIDRoot() { return btm_cb.devcb.id_keys.irk; }
+const Octet16& BTM_GetDeviceIDRoot() {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_GetDeviceIDRoot();
+  }
+  return btm_cb.devcb.id_keys.irk;
+}
 
 /** Return local device DHK. */
-const Octet16& BTM_GetDeviceDHK() { return btm_cb.devcb.id_keys.dhk; }
+const Octet16& BTM_GetDeviceDHK() {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_GetDeviceDHK();
+  }
+  return btm_cb.devcb.id_keys.dhk;
+}
 
 /*******************************************************************************
  *
@@ -214,6 +242,10 @@
 void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
                             RawAddress& local_conn_addr,
                             tBLE_ADDR_TYPE* p_addr_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadConnectionAddr(remote_bda, local_conn_addr,
+                                                   p_addr_type);
+  }
   tACL_CONN* p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
 
   if (p_acl == NULL) {
@@ -238,6 +270,9 @@
  *
  ******************************************************************************/
 bool BTM_IsBleConnection(uint16_t conn_handle) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_IsBleConnection(conn_handle);
+  }
   uint8_t xx;
   tACL_CONN* p;
 
@@ -268,6 +303,10 @@
 bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
                                   RawAddress& conn_addr,
                                   tBLE_ADDR_TYPE* p_addr_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadRemoteConnectionAddr(pseudo_addr, conn_addr,
+                                                         p_addr_type);
+  }
   bool st = true;
 #if (BLE_PRIVACY_SPT == TRUE)
   tACL_CONN* p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
@@ -306,6 +345,9 @@
  *
  ******************************************************************************/
 void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SecurityGrant(bd_addr, res);
+  }
   tSMP_STATUS res_smp =
       (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
   BTM_TRACE_DEBUG("BTM_SecurityGrant");
@@ -330,6 +372,9 @@
  ******************************************************************************/
 void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
                          uint32_t passkey) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BlePasskeyReply(bd_addr, res, passkey);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
   tSMP_STATUS res_smp =
       (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
@@ -357,6 +402,9 @@
  *
  ******************************************************************************/
 void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleConfirmReply(bd_addr, res);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
   tSMP_STATUS res_smp =
       (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
@@ -388,6 +436,9 @@
  ******************************************************************************/
 void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
                          uint8_t* p_data) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleOobDataReply(bd_addr, res, len, p_data);
+  }
   tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
 
@@ -417,6 +468,10 @@
  ******************************************************************************/
 void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
                                          uint8_t* p_c, uint8_t* p_r) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSecureConnectionOobDataReply(bd_addr, p_c,
+                                                                p_r);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
 
   BTM_TRACE_DEBUG("%s:", __func__);
@@ -453,6 +508,10 @@
  *
  ******************************************************************************/
 void BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSetConnScanParams(scan_interval,
+                                                     scan_window);
+  }
   tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
   bool new_param = false;
 
@@ -498,6 +557,10 @@
 void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
                               uint16_t max_conn_int, uint16_t slave_latency,
                               uint16_t supervision_tout) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSetPrefConnParams(
+        bd_addr, min_conn_int, max_conn_int, slave_latency, supervision_tout);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
 
   BTM_TRACE_API(
@@ -617,6 +680,10 @@
  ******************************************************************************/
 bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
                                        tBT_TRANSPORT transport) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadConnectedTransportAddress(remote_bda,
+                                                              transport);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*remote_bda);
 
   /* if no device can be located, return */
@@ -655,6 +722,9 @@
  *
  ******************************************************************************/
 void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleReceiverTest(rx_freq, p_cmd_cmpl_cback);
+  }
   btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
 
   btsnd_hcic_ble_receiver_test(rx_freq);
@@ -676,6 +746,10 @@
 void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
                             uint8_t packet_payload,
                             tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleTransmitterTest(
+        tx_freq, test_data_len, packet_payload, p_cmd_cmpl_cback);
+  }
   btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
   btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload);
 }
@@ -691,6 +765,9 @@
  *
  ******************************************************************************/
 void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleTestEnd(p_cmd_cmpl_cback);
+  }
   btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
 
   btsnd_hcic_ble_test_end();
@@ -720,6 +797,9 @@
  *
  ******************************************************************************/
 bool BTM_UseLeLink(const RawAddress& bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_UseLeLink(bd_addr);
+  }
   tACL_CONN* p;
   tBT_DEVICE_TYPE dev_type;
   tBLE_ADDR_TYPE addr_type;
@@ -751,6 +831,9 @@
  ******************************************************************************/
 tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
                                  uint16_t tx_pdu_length) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetBleDataLength(bd_addr, tx_pdu_length);
+  }
   tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
   uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY;
 
@@ -819,6 +902,9 @@
 void BTM_BleReadPhy(
     const RawAddress& bd_addr,
     base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleReadPhy(bd_addr, cb);
+  }
   BTM_TRACE_DEBUG("%s", __func__);
 
   tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
@@ -866,6 +952,9 @@
  ******************************************************************************/
 tBTM_STATUS BTM_BleSetDefaultPhy(uint8_t all_phys, uint8_t tx_phys,
                                  uint8_t rx_phys) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSetDefaultPhy(all_phys, tx_phys, rx_phys);
+  }
   BTM_TRACE_DEBUG("%s: all_phys = 0x%02x, tx_phys = 0x%02x, rx_phys = 0x%02x",
                   __func__, all_phys, tx_phys, rx_phys);
 
@@ -905,6 +994,10 @@
  ******************************************************************************/
 void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
                    uint16_t phy_options) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSetPhy(bd_addr, tx_phys, rx_phys,
+                                          phy_options);
+  }
   tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
 
   if (p_acl == NULL) {
@@ -2035,6 +2128,10 @@
  ******************************************************************************/
 bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
                           uint16_t len, BLE_SIGNATURE signature) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleDataSignature(bd_addr, p_text, len,
+                                                 signature);
+  }
   tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
 
   BTM_TRACE_DEBUG("%s", __func__);
@@ -2093,6 +2190,10 @@
  ******************************************************************************/
 bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
                             uint16_t len, uint32_t counter, uint8_t* p_comp) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleVerifySignature(bd_addr, p_orig, len,
+                                                   counter, p_comp);
+  }
   bool verified = false;
   tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
   uint8_t p_mac[BTM_CMAC_TLEN_SIZE];
@@ -2130,6 +2231,10 @@
 bool BTM_GetLeSecurityState(const RawAddress& bd_addr,
                             uint8_t* p_le_dev_sec_flags,
                             uint8_t* p_le_key_size) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_GetLeSecurityState(bd_addr, p_le_dev_sec_flags,
+                                                   p_le_key_size);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec;
   uint16_t dev_rec_sec_flags;
 
@@ -2186,6 +2291,9 @@
  *
  ******************************************************************************/
 bool BTM_BleSecurityProcedureIsRunning(const RawAddress& bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleSecurityProcedureIsRunning(bd_addr);
+  }
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
 
   if (p_dev_rec == NULL) {
@@ -2210,6 +2318,9 @@
  *
  ******************************************************************************/
 extern uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_BleGetSupportedKeySize(bd_addr);
+  }
 #if (L2CAP_LE_COC_INCLUDED == TRUE)
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
   tBTM_LE_EVT_DATA btm_le_evt_data;
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index f69f1a2..708e7c2 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -316,7 +316,7 @@
 
   /* send local name filter */
   btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+      FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
       base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_LOCAL_NAME, cb));
 
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -379,7 +379,7 @@
   }
 
   btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+      FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
       base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_MANU_DATA, cb));
 
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -417,7 +417,7 @@
   }
 
   btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+      FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
       base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_SRVC_DATA, cb));
 
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -520,7 +520,7 @@
 
   /* send address filter */
   btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+      FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
       base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_ADDR, cb));
 
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -591,7 +591,7 @@
   }
 
   /* send UUID filter update */
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
                             base::Bind(&btm_flt_update_cb, evt_type, cb));
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
 }
@@ -716,7 +716,7 @@
   UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR);
 
   btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+      FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
       base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
 
   memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -801,7 +801,7 @@
             BTM_BLE_ADV_FILT_TRACK_NUM;
 
     btu_hcif_send_cmd_with_cb(
-        FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+        FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
         base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
   } else if (BTM_BLE_SCAN_COND_DELETE == action) {
     /* select feature based on control block settings */
@@ -811,7 +811,7 @@
     UINT8_TO_STREAM(p, filt_index);
 
     btu_hcif_send_cmd_with_cb(
-        FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+        FROM_HERE, HCI_BLE_ADV_FILTER, param,
         (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH),
         base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
   } else if (BTM_BLE_SCAN_COND_CLEAR == action) {
@@ -823,7 +823,7 @@
     UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
 
     btu_hcif_send_cmd_with_cb(
-        FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+        FROM_HERE, HCI_BLE_ADV_FILTER, param,
         (uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH - 1),
         base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
   }
@@ -874,7 +874,7 @@
   UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE);
   UINT8_TO_STREAM(p, enable);
 
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param,
                             BTM_BLE_PCF_ENABLE_LEN,
                             base::Bind(&enable_cmpl_cback, p_stat_cback));
 }
diff --git a/stack/btm/btm_ble_batchscan.cc b/stack/btm/btm_ble_batchscan.cc
index 89b3e6c..f7d5d3c 100644
--- a/stack/btm/btm_ble_batchscan.cc
+++ b/stack/btm/btm_ble_batchscan.cc
@@ -240,7 +240,7 @@
   UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
   UINT8_TO_STREAM(pp, scan_mode);
 
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
 }
 
 /* read reports. data is accumulated in |data_all|, number of records is
@@ -311,7 +311,7 @@
   UINT8_TO_STREAM(pp, batch_scan_trunc_max);
   UINT8_TO_STREAM(pp, batch_scan_notify_threshold);
 
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
 }
 
 /* This function writes the batch scan params in controller */
@@ -336,7 +336,7 @@
   UINT8_TO_STREAM(p, addr_type);
   UINT8_TO_STREAM(p, discard_rule);
 
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
 }
 
 /* This function enables the customer specific feature in controller */
@@ -349,7 +349,7 @@
   UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
   UINT8_TO_STREAM(p, 0x01 /* enable */);
 
-  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
 }
 
 }  // namespace
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 73256c8..dbeb103 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -39,6 +39,7 @@
     uint16_t conn_timeout, uint16_t min_ce_len, uint16_t max_ce_len,
     uint8_t phy);
 extern void btm_ble_create_conn_cancel();
+void wl_remove_complete(uint8_t* p_data, uint16_t /* evt_len */);
 
 // Unfortunately (for now?) we have to maintain a copy of the device whitelist
 // on the host to determine if a device is pending to be connected or not. This
@@ -72,7 +73,14 @@
         BackgroundConnection{address, addr_type, false, 0, false};
   } else {
     BackgroundConnection* connection = &map_iter->second;
-    connection->addr_type = addr_type;
+    if (addr_type != connection->addr_type) {
+      LOG(INFO) << __func__ << " Addr type mismatch " << address;
+      btsnd_hcic_ble_remove_from_white_list(
+        connection->addr_type_in_wl, connection->address,
+        base::Bind(&wl_remove_complete));
+      connection->addr_type = addr_type;
+      connection->in_controller_wl = false;
+    }
     connection->pending_removal = false;
   }
 }
@@ -170,8 +178,7 @@
     return true;
 
   // bonded device with identity address known
-  if (p_dev_rec->ble.identity_addr != address &&
-      !p_dev_rec->ble.identity_addr.IsEmpty()) {
+  if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
     return true;
   }
 
@@ -197,8 +204,7 @@
 
   if (p_dev_rec != NULL && p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) {
     if (to_add) {
-      if (p_dev_rec->ble.identity_addr != bd_addr &&
-          !p_dev_rec->ble.identity_addr.IsEmpty()) {
+      if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
         background_connection_add(p_dev_rec->ble.identity_addr_type,
                                   p_dev_rec->ble.identity_addr);
       } else {
@@ -212,8 +218,7 @@
 
       p_dev_rec->ble.in_controller_list |= BTM_WHITE_LIST_BIT;
     } else {
-      if (!p_dev_rec->ble.identity_addr.IsEmpty() &&
-          p_dev_rec->ble.identity_addr != bd_addr) {
+      if (!p_dev_rec->ble.identity_addr.IsEmpty()) {
         background_connection_remove(p_dev_rec->ble.identity_addr);
       } else {
         background_connection_remove(bd_addr);
@@ -306,6 +311,14 @@
   BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
 }
 
+uint8_t BTM_GetWhiteListSize() {
+  const controller_t* controller = controller_get_interface();
+  if (!controller->supports_ble()) {
+    return 0;
+  }
+  return controller->get_ble_white_list_size();
+}
+
 bool BTM_SetLeConnectionModeToFast() {
   VLOG(2) << __func__;
   tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
diff --git a/stack/btm/btm_ble_bgconn.h b/stack/btm/btm_ble_bgconn.h
index 45ab2ec..407f513 100644
--- a/stack/btm/btm_ble_bgconn.h
+++ b/stack/btm/btm_ble_bgconn.h
@@ -25,6 +25,9 @@
 /** Removes the device from white list */
 extern void BTM_WhiteListRemove(const RawAddress& address);
 
+/** Get max white list size supports of the Bluetooth controller */
+extern uint8_t BTM_GetWhiteListSize();
+
 /** Clear the whitelist, end any pending whitelist connections */
 extern void BTM_WhiteListClear();
 
@@ -37,4 +40,4 @@
 /* Use slow scan window/interval for LE connection establishment.
  * This does not send any requests to controller, instead it changes the
  * parameters that will be used after next add/remove request */
-extern void BTM_SetLeConnectionModeToSlow();
\ No newline at end of file
+extern void BTM_SetLeConnectionModeToSlow();
diff --git a/stack/btm/btm_ble_connection_establishment.cc b/stack/btm/btm_ble_connection_establishment.cc
index c0d7791..77bc00f 100644
--- a/stack/btm/btm_ble_connection_establishment.cc
+++ b/stack/btm/btm_ble_connection_establishment.cc
@@ -159,6 +159,7 @@
         if (!btm_ble_init_pseudo_addr(match_rec, bda)) {
           /* assign the original address to be the current report address */
           bda = match_rec->ble.pseudo_addr;
+          bda_type = match_rec->ble.ble_addr_type;
         } else {
           bda = match_rec->bd_addr;
         }
diff --git a/stack/btm/btm_ble_cont_energy.cc b/stack/btm/btm_ble_cont_energy.cc
index 4e87308..23fe709 100644
--- a/stack/btm/btm_ble_cont_energy.cc
+++ b/stack/btm/btm_ble_cont_energy.cc
@@ -93,7 +93,7 @@
   }
 
   ble_energy_info_cb.p_ener_cback = p_ener_cback;
-  BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
+  BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO, 0, NULL,
                             btm_ble_cont_energy_cmpl_cback);
   return BTM_CMD_STARTED;
 }
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index ca40a2b..3bb29d1 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -58,7 +58,10 @@
 
 #define BTM_EXT_BLE_RMT_NAME_TIMEOUT_MS (30 * 1000)
 #define MIN_ADV_LENGTH 2
-#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE 9
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN 9
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_L_RELEASE \
+  BTM_VSC_CHIP_CAPABILITY_RSP_LEN
+#define BTM_VSC_CHIP_CAPABILITY_RSP_LEN_M_RELEASE 15
 
 namespace {
 
@@ -472,7 +475,7 @@
  *
  * Function         btm_vsc_brcm_features_complete
  *
- * Description      Command Complete callback for HCI_BLE_VENDOR_CAP_OCF
+ * Description      Command Complete callback for HCI_BLE_VENDOR_CAP
  *
  * Returns          void
  *
@@ -485,7 +488,7 @@
   BTM_TRACE_DEBUG("%s", __func__);
 
   /* Check status of command complete event */
-  CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF);
+  CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP);
   CHECK(p_vcs_cplt_params->param_len > 0);
 
   p = p_vcs_cplt_params->p_param_buf;
@@ -495,6 +498,7 @@
     BTM_TRACE_DEBUG("%s: Status = 0x%02x (0 is success)", __func__, status);
     return;
   }
+  CHECK(p_vcs_cplt_params->param_len >= BTM_VSC_CHIP_CAPABILITY_RSP_LEN);
   STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
   STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
   STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
@@ -512,6 +516,7 @@
 
   if (btm_cb.cmn_ble_vsc_cb.version_supported >=
       BTM_VSC_CHIP_CAPABILITY_M_VERSION) {
+    CHECK(p_vcs_cplt_params->param_len >= BTM_VSC_CHIP_CAPABILITY_RSP_LEN_M_RELEASE);
     STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.total_trackable_advertisers, p);
     STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.extended_scan_support, p);
     STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.debug_logging_supported, p);
@@ -582,7 +587,7 @@
   BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures");
 
   p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback;
-  BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP_OCF, 0, NULL,
+  BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP, 0, NULL,
                             btm_ble_vendor_capability_vsc_cmpl_cback);
 }
 #else
@@ -1473,7 +1478,7 @@
   if (!adv_data.empty()) {
     const uint8_t* p_flag = AdvertiseDataParser::GetFieldByType(
         adv_data, BTM_BLE_AD_TYPE_FLAG, &data_len);
-    if (p_flag != NULL) {
+    if (p_flag != NULL && data_len != 0) {
       flag = *p_flag;
 
       if ((btm_cb.btm_inq_vars.inq_active & BTM_BLE_GENERAL_INQUIRY) &&
@@ -1659,7 +1664,7 @@
   if (!data.empty()) {
     const uint8_t* p_flag =
         AdvertiseDataParser::GetFieldByType(data, BTM_BLE_AD_TYPE_FLAG, &len);
-    if (p_flag != NULL) p_cur->flag = *p_flag;
+    if (p_flag != NULL && len != 0) p_cur->flag = *p_flag;
   }
 
   if (!data.empty()) {
@@ -1750,6 +1755,7 @@
       } else {
         // Assign the original address to be the current report address
         bda = match_rec->ble.pseudo_addr;
+        *addr_type = match_rec->ble.ble_addr_type;
       }
     }
   }
diff --git a/stack/btm/btm_devctl.cc b/stack/btm/btm_devctl.cc
index bc3fb56..5d4a4aa 100644
--- a/stack/btm/btm_devctl.cc
+++ b/stack/btm/btm_devctl.cc
@@ -43,6 +43,9 @@
 #include "stack/gatt/connection_manager.h"
 
 #include "gatt_int.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/controller.h"
+#include "main/shim/shim.h"
 
 extern bluetooth::common::MessageLoopThread bt_startup_thread;
 
@@ -231,8 +234,13 @@
   /* Clear the callback, so application would not hang on reset */
   btm_db_reset();
 
-  module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
-                                     &bt_startup_thread, reset_complete);
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    module_start_up_callbacked_wrapper(get_module(GD_CONTROLLER_MODULE),
+                                       &bt_startup_thread, reset_complete);
+  } else {
+    module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
+                                       &bt_startup_thread, reset_complete);
+  }
 }
 
 /*******************************************************************************
@@ -272,6 +280,7 @@
  ******************************************************************************/
 static void btm_decode_ext_features_page(uint8_t page_number,
                                          const uint8_t* p_features) {
+  CHECK(p_features != nullptr);
   BTM_TRACE_DEBUG("btm_decode_ext_features_page page: %d", page_number);
   switch (page_number) {
     /* Extended (Legacy) Page 0 */
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index 1a5d7f5..aaadd2b 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -42,6 +42,8 @@
 #include "btu.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/shim.h"
 
 using bluetooth::Uuid;
 
@@ -142,6 +144,10 @@
  ******************************************************************************/
 tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
                                    uint16_t interval) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetDiscoverability(inq_mode, window, interval);
+  }
+
   uint8_t scan_mode = 0;
   uint16_t service_class;
   uint8_t* p_cod;
@@ -252,6 +258,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetInquiryScanType(scan_type);
+  }
+
   BTM_TRACE_API("BTM_SetInquiryScanType");
   if (scan_type != BTM_SCAN_TYPE_STANDARD &&
       scan_type != BTM_SCAN_TYPE_INTERLACED)
@@ -285,6 +295,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetPageScanType(scan_type);
+  }
+
   BTM_TRACE_API("BTM_SetPageScanType");
   if (scan_type != BTM_SCAN_TYPE_STANDARD &&
       scan_type != BTM_SCAN_TYPE_INTERLACED)
@@ -321,6 +335,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetInquiryMode(mode);
+  }
+
   const controller_t* controller = controller_get_interface();
   BTM_TRACE_API("BTM_SetInquiryMode");
   if (mode == BTM_INQ_RESULT_STANDARD) {
@@ -356,6 +374,10 @@
  *
  ******************************************************************************/
 uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadDiscoverability(p_window, p_interval);
+  }
+
   BTM_TRACE_API("BTM_ReadDiscoverability");
   if (p_window) *p_window = btm_cb.btm_inq_vars.inq_scan_window;
 
@@ -405,6 +427,11 @@
 tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS* p_inqparms,
                                        uint16_t max_delay, uint16_t min_delay,
                                        tBTM_INQ_RESULTS_CB* p_results_cb) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetPeriodicInquiryMode(p_inqparms, max_delay,
+                                                       min_delay, p_results_cb);
+  }
+
   tBTM_STATUS status;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
 
@@ -492,6 +519,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_CancelPeriodicInquiry(void) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_CancelPeriodicInquiry();
+  }
+
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
   tBTM_STATUS status = BTM_SUCCESS;
   BTM_TRACE_API("BTM_CancelPeriodicInquiry called");
@@ -534,6 +565,10 @@
  ******************************************************************************/
 tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
                                   uint16_t interval) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_SetConnectability(page_mode, window, interval);
+  }
+
   uint8_t scan_mode = 0;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
 
@@ -608,6 +643,10 @@
  *
  ******************************************************************************/
 uint16_t BTM_ReadConnectability(uint16_t* p_window, uint16_t* p_interval) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadConnectability(p_window, p_interval);
+  }
+
   BTM_TRACE_API("BTM_ReadConnectability");
   if (p_window) *p_window = btm_cb.btm_inq_vars.page_scan_window;
 
@@ -630,6 +669,10 @@
  *
  ******************************************************************************/
 uint16_t BTM_IsInquiryActive(void) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_IsInquiryActive();
+  }
+
   BTM_TRACE_API("BTM_IsInquiryActive");
 
   return (btm_cb.btm_inq_vars.inq_active);
@@ -647,6 +690,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_CancelInquiry(void) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_CancelInquiry();
+  }
+
   tBTM_STATUS status = BTM_SUCCESS;
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
   BTM_TRACE_API("BTM_CancelInquiry called");
@@ -733,6 +780,19 @@
                              tBTM_CMPL_CB* p_cmpl_cb) {
   tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
 
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    p_inq->state = BTM_INQ_ACTIVE_STATE;
+    p_inq->p_inq_cmpl_cb = p_cmpl_cb;
+    p_inq->p_inq_results_cb = p_results_cb;
+    p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+    p_inq->inq_active = p_inqparms->mode;
+
+    btm_acl_update_busy_level(BTM_BLI_INQ_EVT);
+
+    return bluetooth::shim::BTM_StartInquiry(p_inqparms, p_results_cb,
+                                             p_cmpl_cb);
+  }
+
   BTM_TRACE_API("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
                 p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
                 p_inqparms->filter_cond_type);
@@ -878,6 +938,11 @@
 tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
                                      tBTM_CMPL_CB* p_cb,
                                      tBT_TRANSPORT transport) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadRemoteDeviceName(remote_bda, p_cb,
+                                                     transport);
+  }
+
   VLOG(1) << __func__ << ": bd addr " << remote_bda;
   /* Use LE transport when LE is the only available option */
   if (transport == BT_TRANSPORT_LE) {
@@ -1039,6 +1104,10 @@
  *
  ******************************************************************************/
 tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::BTM_ReadInquiryRspTxPower(p_cb);
+  }
+
   if (btm_cb.devcb.p_inq_tx_power_cmpl_cb) return (BTM_BUSY);
 
   btm_cb.devcb.p_inq_tx_power_cmpl_cb = p_cb;
@@ -1655,7 +1724,6 @@
     }
 
     p_i = btm_inq_db_find(bda);
-
     /* Only process the num_resp is smaller than max_resps.
        If results are queued to BTU task while canceling inquiry,
        or when more than one result is in this response, > max_resp
@@ -1675,8 +1743,8 @@
 
     /* Check if this address has already been processed for this inquiry */
     if (btm_inq_find_bdaddr(bda)) {
-      /* BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]",
-                      bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/
+      /* BTM_TRACE_DEBUG("BDA seen before %s", bda.ToString().c_str()); */
+
       /* By default suppose no update needed */
       i_rssi = (int8_t)rssi;
 
@@ -1783,9 +1851,12 @@
         p_eir_data = NULL;
 
       /* If a callback is registered, call it with the results */
-      if (p_inq_results_cb)
+      if (p_inq_results_cb) {
         (p_inq_results_cb)((tBTM_INQ_RESULTS*)p_cur, p_eir_data,
                            HCI_EXT_INQ_RESPONSE_LEN);
+      } else {
+        BTM_TRACE_DEBUG("No callback is registered");
+      }
     }
   }
 }
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 4db757e..935903d 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -3774,6 +3774,7 @@
   tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
   tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
   bool are_bonding = false;
+  bool was_authenticating = false;
 
   if (p_dev_rec) {
     VLOG(2) << __func__ << ": Security Manager: in state: "
@@ -3814,16 +3815,35 @@
 
   if (!p_dev_rec) return;
 
-  if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
-      (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
-      (p_dev_rec->bd_addr == btm_cb.pairing_bda))
-    are_bonding = true;
+  if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+    p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+    was_authenticating = true;
+    /* There can be a race condition, when we are starting authentication
+     * and the peer device is doing encryption.
+     * If first we receive encryption change up, then initiated
+     * authentication can not be performed.
+     * According to the spec we can not do authentication on the
+     * encrypted link, so device is correct.
+     */
+    if ((status == HCI_ERR_COMMAND_DISALLOWED) &&
+        ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
+         (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
+      status = HCI_SUCCESS;
+    }
+    if (status == HCI_SUCCESS) {
+      p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+    }
+  }
 
   if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
-      (p_dev_rec->bd_addr == btm_cb.pairing_bda))
+      (p_dev_rec->bd_addr == btm_cb.pairing_bda)) {
+    if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+      are_bonding = true;
+    }
     btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+  }
 
-  if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+  if (was_authenticating == false) {
     if ((btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS) &&
         (old_state != BTM_PAIR_STATE_IDLE)) {
       (*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
@@ -3833,17 +3853,6 @@
     return;
   }
 
-  /* There can be a race condition, when we are starting authentication and
-  ** the peer device is doing encryption.
-  ** If first we receive encryption change up, then initiated authentication
-  ** can not be performed.  According to the spec we can not do authentication
-  ** on the encrypted link, so device is correct.
-  */
-  if ((status == HCI_ERR_COMMAND_DISALLOWED) &&
-      ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
-       (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
-    status = HCI_SUCCESS;
-  }
   /* Currently we do not notify user if it is a keyboard which connects */
   /* User probably Disabled the keyboard while it was asleap.  Let her try */
   if (btm_cb.api.p_auth_complete_callback) {
@@ -3854,8 +3863,6 @@
                                              p_dev_rec->sec_bd_name, status);
   }
 
-  p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
-
   /* If this is a bonding procedure can disconnect the link now */
   if (are_bonding) {
     p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
@@ -3901,8 +3908,6 @@
     return;
   }
 
-  p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
-
   if (p_dev_rec->pin_code_length >= 16 ||
       p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
       p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
@@ -4305,12 +4310,15 @@
       }
     }
 
-    if (!addr_matched) {
-      /* Don't callback unless this Connection-Complete-failure event has the
-       * same mac address as the bonding device */
+    /* p_auth_complete_callback might have freed the p_dev_rec, ensure it exists
+     * before accessing */
+    p_dev_rec = btm_find_dev(bda);
+    if (!p_dev_rec) {
+      /* Don't callback when device security record was removed */
       VLOG(1) << __func__
-              << ": Different mac addresses: pairing_bda=" << btm_cb.pairing_bda
-              << ", bda=" << bda << ", do not callback";
+              << ": device security record associated with this bda has been "
+                 "removed! bda="
+              << bda << ", do not callback!";
       return;
     }
 
@@ -4552,8 +4560,7 @@
    */
   if (is_sample_ltk(p_dev_rec->ble.keys.pltk)) {
     android_errorWriteLog(0x534e4554, "128437297");
-    LOG(INFO) << __func__ << " removing bond to device that used sample LTK: "
-              << p_dev_rec->bd_addr;
+    LOG(INFO) << __func__ << " removing bond to device that used sample LTK: " << p_dev_rec->bd_addr;
 
     bta_dm_remove_device(p_dev_rec->bd_addr);
   }
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index b9543fd..2035cc6 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -57,6 +57,7 @@
 using base::Location;
 
 extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_process_inq_results2(uint8_t* p, uint8_t inq_res_mode);
 extern void btm_ble_test_command_complete(uint8_t* p);
 extern void smp_cancel_start_encryption_attempt();
 
@@ -1129,8 +1130,16 @@
 
 constexpr uint8_t MIN_KEY_SIZE = 7;
 
-static void read_encryption_key_size_complete_after_encryption_change(
-    uint8_t status, uint16_t handle, uint8_t key_size) {
+static void read_encryption_key_size_complete_after_encryption_change(uint8_t status, uint16_t handle,
+                                                                      uint8_t key_size) {
+  if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
+    /* If remote device stop the encryption before we call "Read Encryption Key
+     * Size", we might receive Insufficient Security, which means that link is
+     * no longer encrypted. */
+    LOG(INFO) << __func__ << ": encryption stopped on link: " << loghex(handle);
+    return;
+  }
+
   if (status != HCI_SUCCESS) {
     LOG(INFO) << __func__ << ": disconnecting, status: " << loghex(status);
     btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
@@ -1139,9 +1148,8 @@
 
   if (key_size < MIN_KEY_SIZE) {
     android_errorWriteLog(0x534e4554, "124301137");
-    LOG(ERROR) << __func__
-               << " encryption key too short, disconnecting. handle: "
-               << loghex(handle) << " key_size: " << +key_size;
+    LOG(ERROR) << __func__ << " encryption key too short, disconnecting. handle: " << loghex(handle)
+               << " key_size: " << +key_size;
 
     btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
     return;
@@ -1169,14 +1177,16 @@
   STREAM_TO_UINT16(handle, p);
   STREAM_TO_UINT8(encr_enable, p);
 
-  if (status != HCI_SUCCESS || encr_enable == 0 ||
-      BTM_IsBleConnection(handle)) {
+  if (status != HCI_SUCCESS || encr_enable == 0 || BTM_IsBleConnection(handle)) {
+    if (status == HCI_ERR_CONNECTION_TOUT) {
+      smp_cancel_start_encryption_attempt();
+      return;
+    }
+
     btm_acl_encrypt_change(handle, status, encr_enable);
     btm_sec_encrypt_change(handle, status, encr_enable);
   } else {
-    btsnd_hcic_read_encryption_key_size(
-        handle,
-        base::Bind(&read_encryption_key_size_complete_after_encryption_change));
+    btsnd_hcic_read_encryption_key_size(handle, base::Bind(&read_encryption_key_size_complete_after_encryption_change));
   }
 }
 
@@ -2049,8 +2059,15 @@
  * End of Simple Pairing Events
  **********************************************/
 
-static void read_encryption_key_size_complete_after_key_refresh(
-    uint8_t status, uint16_t handle, uint8_t key_size) {
+static void read_encryption_key_size_complete_after_key_refresh(uint8_t status, uint16_t handle, uint8_t key_size) {
+  if (status == HCI_ERR_INSUFFCIENT_SECURITY) {
+    /* If remote device stop the encryption before we call "Read Encryption Key
+     * Size", we might receive Insufficient Security, which means that link is
+     * no longer encrypted. */
+    LOG(INFO) << __func__ << ": encryption stopped on link: " << loghex(handle);
+    return;
+  }
+
   if (status != HCI_SUCCESS) {
     LOG(INFO) << __func__ << ": disconnecting, status: " << loghex(status);
     btsnd_hcic_disconnect(handle, HCI_ERR_PEER_USER);
@@ -2059,9 +2076,8 @@
 
   if (key_size < MIN_KEY_SIZE) {
     android_errorWriteLog(0x534e4554, "124301137");
-    LOG(ERROR) << __func__
-               << " encryption key too short, disconnecting. handle: "
-               << loghex(handle) << " key_size: " << +key_size;
+    LOG(ERROR) << __func__ << " encryption key too short, disconnecting. handle: " << loghex(handle)
+               << " key_size: " << +key_size;
 
     btsnd_hcic_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY);
     return;
@@ -2080,9 +2096,7 @@
   if (status != HCI_SUCCESS || BTM_IsBleConnection(handle)) {
     btm_sec_encrypt_change(handle, status, (status == HCI_SUCCESS) ? 1 : 0);
   } else {
-    btsnd_hcic_read_encryption_key_size(
-        handle,
-        base::Bind(&read_encryption_key_size_complete_after_key_refresh));
+    btsnd_hcic_read_encryption_key_size(handle, base::Bind(&read_encryption_key_size_complete_after_key_refresh));
   }
 }
 
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index 49c9697..8838206 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -71,6 +71,11 @@
       btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
       break;
 
+    case BT_EVT_TO_BTU_HCI_ISO:
+      // TODO: implement handler
+      osi_free(p_msg);
+      break;
+
     default:
       osi_free(p_msg);
       break;
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index cce62d4..e71238f 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -411,23 +411,26 @@
   Uuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
 
   btgatt_db_element_t service[] = {
-    {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = svc_uuid},
-    {.type = BTGATT_DB_CHARACTERISTIC,
-     .uuid = name_uuid,
+    {
+        .uuid = svc_uuid,
+        .type = BTGATT_DB_PRIMARY_SERVICE,
+    },
+    {.uuid = name_uuid,
+     .type = BTGATT_DB_CHARACTERISTIC,
      .properties = GATT_CHAR_PROP_BIT_READ,
      .permissions = GATT_PERM_READ},
-    {.type = BTGATT_DB_CHARACTERISTIC,
-     .uuid = icon_uuid,
+    {.uuid = icon_uuid,
+     .type = BTGATT_DB_CHARACTERISTIC,
      .properties = GATT_CHAR_PROP_BIT_READ,
      .permissions = GATT_PERM_READ},
-    {.type = BTGATT_DB_CHARACTERISTIC,
-     .uuid = addr_res_uuid,
+    {.uuid = addr_res_uuid,
+     .type = BTGATT_DB_CHARACTERISTIC,
      .properties = GATT_CHAR_PROP_BIT_READ,
      .permissions = GATT_PERM_READ}
 #if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
     ,
-    {.type = BTGATT_DB_CHARACTERISTIC,
-     .uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),
+    {.uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),
+     .type = BTGATT_DB_CHARACTERISTIC,
      .properties = GATT_CHAR_PROP_BIT_READ,
      .permissions = GATT_PERM_READ}
 #endif
diff --git a/stack/gap/gap_conn.cc b/stack/gap/gap_conn.cc
index 72183bb..15d3ddb 100644
--- a/stack/gap/gap_conn.cc
+++ b/stack/gap/gap_conn.cc
@@ -235,8 +235,7 @@
 
   /* Register the PSM with L2CAP */
   if (transport == BT_TRANSPORT_BR_EDR) {
-    p_ccb->psm = L2CA_REGISTER(
-        psm, &conn.reg_info, AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+    p_ccb->psm = L2CA_REGISTER(psm, &conn.reg_info, false /* enable_snoop */);
     if (p_ccb->psm == 0) {
       LOG(ERROR) << StringPrintf("%s: Failure registering PSM 0x%04x", __func__,
                                  psm);
diff --git a/stack/gatt/connection_manager.cc b/stack/gatt/connection_manager.cc
index cfbb02e..9454be0 100644
--- a/stack/gatt/connection_manager.cc
+++ b/stack/gatt/connection_manager.cc
@@ -267,12 +267,11 @@
 void dump(int fd) {
   dprintf(fd, "\nconnection_manager state:\n");
   if (bgconn_dev.empty()) {
-    dprintf(fd, "\n\tno Low Energy connection attempts\n");
+    dprintf(fd, "\tno Low Energy connection attempts\n");
     return;
   }
 
-  dprintf(fd, "\n\tdevices attempting connection: %d\n",
-          (int)bgconn_dev.size());
+  dprintf(fd, "\tdevices attempting connection: %d", (int)bgconn_dev.size());
   for (const auto& entry : bgconn_dev) {
     dprintf(fd, "\n\t * %s: ", entry.first.ToString().c_str());
 
@@ -283,13 +282,14 @@
       }
     }
 
-    if (entry.second.doing_bg_conn.empty()) {
+    if (!entry.second.doing_bg_conn.empty()) {
       dprintf(fd, "\n\t\tapps doing background connect: ");
       for (const auto& id : entry.second.doing_bg_conn) {
         dprintf(fd, "%d, ", id);
       }
     }
   }
+  dprintf(fd, "\n");
 }
 
 }  // namespace connection_manager
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index 4195548..5fe9a37 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -382,6 +382,7 @@
   if (it == gatt_cb.srv_list_info->end()) {
     LOG(ERROR) << __func__ << ": service_handle=" << loghex(service_handle)
                << " is not in use";
+    return;
   }
 
   if (it->sdp_handle) {
@@ -707,6 +708,7 @@
   p_clcb->op_subtype = type;
   p_clcb->auth_req = p_read->by_handle.auth_req;
   p_clcb->counter = 0;
+  p_clcb->read_req_current_mtu = p_tcb->payload_size;
 
   switch (type) {
     case GATT_READ_BY_TYPE:
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index 8861a7a..1acfd81 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -285,11 +285,16 @@
   Uuid char_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
 
   btgatt_db_element_t service[] = {
-      {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = service_uuid},
-      {.type = BTGATT_DB_CHARACTERISTIC,
-       .uuid = char_uuid,
-       .properties = GATT_CHAR_PROP_BIT_INDICATE,
-       .permissions = 0}};
+      {
+          .uuid = service_uuid,
+          .type = BTGATT_DB_PRIMARY_SERVICE,
+      },
+      {
+          .uuid = char_uuid,
+          .type = BTGATT_DB_CHARACTERISTIC,
+          .properties = GATT_CHAR_PROP_BIT_INDICATE,
+          .permissions = 0,
+      }};
 
   GATTS_AddService(gatt_cb.gatt_if, service,
                    sizeof(service) / sizeof(btgatt_db_element_t));
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index 2650a30..6bc01e1 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -627,6 +627,10 @@
   memset(&value, 0, sizeof(value));
   STREAM_TO_UINT16(value.handle, p);
   value.len = len - 2;
+  if (value.len > GATT_MAX_ATTR_LEN) {
+    LOG(ERROR) << "value.len larger than GATT_MAX_ATTR_LEN, discard";
+    return;
+  }
   memcpy(value.value, p, value.len);
 
   if (!GATT_HANDLE_IS_VALID(value.handle)) {
@@ -909,11 +913,18 @@
 
         memcpy(p_clcb->p_attr_buf + offset, p, len);
 
-        /* send next request if needed  */
+        /* full packet for read or read blob rsp */
+        bool packet_is_full;
+        if (tcb.payload_size == p_clcb->read_req_current_mtu) {
+          packet_is_full = (len == (tcb.payload_size - 1));
+        } else {
+          packet_is_full = (len == (p_clcb->read_req_current_mtu - 1) ||
+                            len == (tcb.payload_size - 1));
+          p_clcb->read_req_current_mtu = tcb.payload_size;
+        }
 
-        if (len == (tcb.payload_size -
-                    1) && /* full packet for read or read blob rsp */
-            len + offset < GATT_MAX_ATTR_LEN) {
+        /* send next request if needed  */
+        if (packet_is_full && (len + offset < GATT_MAX_ATTR_LEN)) {
           VLOG(1) << StringPrintf(
               "full pkt issue read blob for remianing bytes old offset=%d "
               "len=%d new offset=%d",
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index 2c00fd7..e072a47 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -323,6 +323,8 @@
   bool in_use;
   alarm_t* gatt_rsp_timer_ent; /* peer response timer */
   uint8_t retry_count;
+  uint16_t read_req_current_mtu; /* This is the MTU value that the read was
+                                    initiated with */
 };
 
 typedef struct {
diff --git a/stack/gatt/gatt_main.cc b/stack/gatt/gatt_main.cc
index b332496..ed8d3fd 100644
--- a/stack/gatt/gatt_main.cc
+++ b/stack/gatt/gatt_main.cc
@@ -124,7 +124,8 @@
   L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
 
   /* Now, register with L2CAP for ATT PSM over BR/EDR */
-  if (!L2CA_Register(BT_PSM_ATT, (tL2CAP_APPL_INFO*)&dyn_info)) {
+  if (!L2CA_Register(BT_PSM_ATT, (tL2CAP_APPL_INFO*)&dyn_info,
+                     false /* enable_snoop */)) {
     LOG(ERROR) << "ATT Dynamic Registration failed";
   }
 
@@ -822,6 +823,9 @@
     }
   }
 
+  /* Remove the direct connection */
+  connection_manager::on_connection_complete(p_tcb->peer_bda);
+
   if (!p_tcb->app_hold_link.empty() && p_tcb->att_lcid == L2CAP_ATT_CID) {
     /* disable idle timeout if one or more clients are holding the link disable
      * the idle timer */
diff --git a/stack/hcic/hcicmds.cc b/stack/hcic/hcicmds.cc
index 2e849a4..23a8648 100644
--- a/stack/hcic/hcicmds.cc
+++ b/stack/hcic/hcicmds.cc
@@ -1309,9 +1309,8 @@
   btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
 }
 
-static void read_encryption_key_size_complete(
-    ReadEncKeySizeCb cb, uint8_t* return_parameters,
-    uint16_t return_parameters_length) {
+static void read_encryption_key_size_complete(ReadEncKeySizeCb cb, uint8_t* return_parameters,
+                                              uint16_t return_parameters_length) {
   uint8_t status;
   uint16_t handle;
   uint8_t key_size;
@@ -1330,9 +1329,8 @@
   uint8_t* p = param;
   UINT16_TO_STREAM(p, handle);
 
-  btu_hcif_send_cmd_with_cb(
-      FROM_HERE, HCI_READ_ENCR_KEY_SIZE, param, len,
-      base::Bind(&read_encryption_key_size_complete, base::Passed(&cb)));
+  btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_READ_ENCR_KEY_SIZE, param, len,
+                            base::Bind(&read_encryption_key_size_complete, base::Passed(&cb)));
 }
 
 void btsnd_hcic_read_failed_contact_counter(uint16_t handle) {
diff --git a/stack/hid/hidd_api.cc b/stack/hid/hidd_api.cc
index f93511e..cd40c2c 100644
--- a/stack/hid/hidd_api.cc
+++ b/stack/hid/hidd_api.cc
@@ -33,7 +33,6 @@
 #include "hidd_api.h"
 #include "hidd_int.h"
 #include "hiddefs.h"
-#include "log/log.h"
 
 tHID_DEV_CTB hd_cb;
 
@@ -321,10 +320,6 @@
       UINT8_TO_BE_STREAM(p, desc_len);
       ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len);
 
-      if (desc_len > HIDD_APP_DESCRIPTOR_LEN - 6) {
-        android_errorWriteLog(0x534e4554, "113572366");
-      }
-
       result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST,
                                  DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf);
 
diff --git a/stack/hid/hidd_conn.cc b/stack/hid/hidd_conn.cc
index e4525f9..55ec3b2 100644
--- a/stack/hid/hidd_conn.cc
+++ b/stack/hid/hidd_conn.cc
@@ -614,6 +614,12 @@
 
   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
 
+  if (p_msg->len < 1) {
+    HIDD_TRACE_ERROR("Invalid data length, ignore");
+    osi_free(p_msg);
+    return;
+  }
+
   p_hcon = &hd_cb.device.conn;
 
   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
@@ -756,12 +762,14 @@
   hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
   hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
 
-  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info,
+                     false /* enable_snoop */)) {
     HIDD_TRACE_ERROR("HID Control (device) registration failed");
     return (HID_ERR_L2CAP_FAILED);
   }
 
-  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info,
+                     false /* enable_snoop */)) {
     L2CA_Deregister(HID_PSM_CONTROL);
     HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
     return (HID_ERR_L2CAP_FAILED);
diff --git a/stack/hid/hidh_conn.cc b/stack/hid/hidh_conn.cc
index 6b729e5..3c694f0 100644
--- a/stack/hid/hidh_conn.cc
+++ b/stack/hid/hidh_conn.cc
@@ -97,11 +97,13 @@
   hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info,
+                     false /* enable_snoop */)) {
     HIDH_TRACE_ERROR("HID-Host Control Registration failed");
     return (HID_ERR_L2CAP_FAILED);
   }
-  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info,
+                     false /* enable_snoop */)) {
     L2CA_Deregister(HID_PSM_CONTROL);
     HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed");
     return (HID_ERR_L2CAP_FAILED);
diff --git a/stack/include/advertise_data_parser.h b/stack/include/advertise_data_parser.h
index b62dbb3..a1ac17b 100644
--- a/stack/include/advertise_data_parser.h
+++ b/stack/include/advertise_data_parser.h
@@ -34,7 +34,8 @@
     auto data_start = ad.begin() + position;
 
     // Traxxas - bad name length
-    if (std::equal(data_start, data_start + 3, trx_quirk.begin()) &&
+    if ((ad.size() - position) >= 18 &&
+        std::equal(data_start, data_start + 3, trx_quirk.begin()) &&
         std::equal(data_start + 5, data_start + 11, trx_quirk.begin() + 5) &&
         std::equal(data_start + 12, data_start + 18, trx_quirk.begin() + 12)) {
       return true;
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 4121a19..01e8248 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -21,7 +21,6 @@
 
 #include <stdbool.h>
 #include <stdint.h>
-#include <string.h>
 
 #ifndef FALSE
 #define FALSE false
@@ -81,6 +80,9 @@
 /* HCI command from upper layer     */
 #define BT_EVT_TO_BTU_HCI_CMD 0x1600
 
+/* ISO Data from HCI                */
+#define BT_EVT_TO_BTU_HCI_ISO 0x1700
+
 /* L2CAP segment(s) transmitted     */
 #define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900
 
@@ -120,6 +122,8 @@
 #define BT_EVT_TO_LM_HCI_ACL_ACK 0x2b00
 /* LM Diagnostics commands          */
 #define BT_EVT_TO_LM_DIAG 0x2c00
+/* HCI ISO Data                     */
+#define BT_EVT_TO_LM_HCI_ISO 0x2d00
 
 #define BT_EVT_TO_BTM_CMDS 0x2f00
 #define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS)
@@ -581,7 +585,9 @@
  * 0x4C68384139F574D836BCF34E9DFB01BF */
 constexpr Octet16 SAMPLE_LTK = {0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
                                 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c};
-inline bool is_sample_ltk(const Octet16& ltk) { return ltk == SAMPLE_LTK; }
+inline bool is_sample_ltk(const Octet16& ltk) {
+  return ltk == SAMPLE_LTK;
+}
 
 #endif
 
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
old mode 100644
new mode 100755
index 965087c..d14b754
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -611,7 +611,7 @@
 constexpr uint8_t PHY_LE_NO_PACKET = 0x00;
 constexpr uint8_t PHY_LE_1M = 0x01;
 constexpr uint8_t PHY_LE_2M = 0x02;
-constexpr uint8_t PHY_LE_CODED = 0x03;
+constexpr uint8_t PHY_LE_CODED = 0x04;
 
 constexpr uint8_t NO_ADI_PRESENT = 0xFF;
 constexpr uint8_t TX_POWER_NOT_PRESENT = 0x7F;
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index ef87b5b..22df8af 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -396,35 +396,35 @@
 #define HCI_BLE_WRITE_RF_COMPENS_POWER (0x004D | HCI_GRP_BLE_CMDS)
 #define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
 
-/* LE Get Vendor Capabilities Command OCF */
-#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
+/* LE Get Vendor Capabilities Command opcode */
+#define HCI_BLE_VENDOR_CAP (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Multi adv OCF */
-#define HCI_BLE_MULTI_ADV_OCF (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
+/* Multi adv opcode */
+#define HCI_BLE_MULTI_ADV (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Batch scan OCF */
-#define HCI_BLE_BATCH_SCAN_OCF (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
+/* Batch scan opcode */
+#define HCI_BLE_BATCH_SCAN (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* ADV filter OCF */
-#define HCI_BLE_ADV_FILTER_OCF (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+/* ADV filter opcode */
+#define HCI_BLE_ADV_FILTER (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Tracking OCF */
-#define HCI_BLE_TRACK_ADV_OCF (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
+/* Tracking opcode */
+#define HCI_BLE_TRACK_ADV (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Energy info OCF */
-#define HCI_BLE_ENERGY_INFO_OCF (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
+/* Energy info opcode */
+#define HCI_BLE_ENERGY_INFO (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Extended BLE Scan parameters OCF */
-#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF (0x015A | HCI_GRP_VENDOR_SPECIFIC)
+/* Extended BLE Scan parameters opcode */
+#define HCI_BLE_EXTENDED_SCAN_PARAMS (0x015A | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Controller debug info OCF */
-#define HCI_CONTROLLER_DEBUG_INFO_OCF (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+/* Controller debug info opcode */
+#define HCI_CONTROLLER_DEBUG_INFO (0x015B | HCI_GRP_VENDOR_SPECIFIC)
 
-/* A2DP offload OCF */
-#define HCI_CONTROLLER_A2DP_OPCODE_OCF (0x015D | HCI_GRP_VENDOR_SPECIFIC)
+/* A2DP offload opcode */
+#define HCI_CONTROLLER_A2DP (0x015D | HCI_GRP_VENDOR_SPECIFIC)
 
-/* Bluetooth Quality Report OCF */
-#define HCI_CONTROLLER_BQR_OPCODE_OCF (0x015E | HCI_GRP_VENDOR_SPECIFIC)
+/* Bluetooth Quality Report opcode */
+#define HCI_CONTROLLER_BQR (0x015E | HCI_GRP_VENDOR_SPECIFIC)
 
 /* subcode for multi adv feature */
 #define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
diff --git a/stack/include/hcimsgs.h b/stack/include/hcimsgs.h
index 5682a5c..285ae41 100644
--- a/stack/include/hcimsgs.h
+++ b/stack/include/hcimsgs.h
@@ -611,8 +611,7 @@
 extern void btsnd_hcic_get_link_quality(uint16_t handle); /* Get Link Quality */
 extern void btsnd_hcic_read_rssi(uint16_t handle);        /* Read RSSI */
 using ReadEncKeySizeCb = base::OnceCallback<void(uint8_t, uint16_t, uint8_t)>;
-extern void btsnd_hcic_read_encryption_key_size(uint16_t handle,
-                                                ReadEncKeySizeCb cb);
+extern void btsnd_hcic_read_encryption_key_size(uint16_t handle, ReadEncKeySizeCb cb);
 extern void btsnd_hcic_read_failed_contact_counter(uint16_t handle);
 extern void btsnd_hcic_read_automatic_flush_timeout(uint16_t handle);
 extern void btsnd_hcic_enable_test_mode(
diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h
index 88121af..8f364e7 100644
--- a/stack/include/l2c_api.h
+++ b/stack/include/l2c_api.h
@@ -328,7 +328,7 @@
 
 } tL2CAP_ERTM_INFO;
 
-#define L2CA_REGISTER(a, b, c) L2CA_Register(a, (tL2CAP_APPL_INFO*)(b))
+#define L2CA_REGISTER(a, b, c) L2CA_Register(a, (tL2CAP_APPL_INFO*)(b), c)
 #define L2CA_DEREGISTER(a) L2CA_Deregister(a)
 #define L2CA_CONNECT_REQ(a, b, c) L2CA_ErtmConnectReq(a, b, c)
 #define L2CA_CONNECT_RSP(a, b, c, d, e, f) L2CA_ErtmConnectRsp(a, b, c, d, e, f)
@@ -362,7 +362,8 @@
  *                  BTM_SetSecurityLevel().
  *
  ******************************************************************************/
-extern uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+extern uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                              bool enable_snoop);
 
 /*******************************************************************************
  *
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index 6dc41de..feab995 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -39,6 +39,8 @@
 #include "hcimsgs.h"
 #include "l2c_int.h"
 #include "l2cdefs.h"
+#include "main/shim/l2c_api.h"
+#include "main/shim/shim.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
 
@@ -58,7 +60,12 @@
  *                  L2CA_ErtmConnectReq() and L2CA_Deregister()
  *
  ******************************************************************************/
-uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                       bool enable_snoop) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_Register(psm, p_cb_info, enable_snoop);
+  }
+
   tL2C_RCB* p_rcb;
   uint16_t vpsm = psm;
 
@@ -104,6 +111,7 @@
     }
   }
 
+  p_rcb->log_packets = enable_snoop;
   p_rcb->api = *p_cb_info;
   p_rcb->real_psm = psm;
 
@@ -121,6 +129,10 @@
  *
  ******************************************************************************/
 void L2CA_Deregister(uint16_t psm) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_Deregister(psm);
+  }
+
   tL2C_RCB* p_rcb;
   tL2C_CCB* p_ccb;
   tL2C_LCB* p_lcb;
@@ -167,6 +179,10 @@
  *
  ******************************************************************************/
 uint16_t L2CA_AllocatePSM(void) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_AllocatePSM();
+  }
+
   bool done = false;
   uint16_t psm = l2cb.dyn_psm;
 
@@ -202,6 +218,10 @@
  *
  ******************************************************************************/
 uint16_t L2CA_AllocateLePSM(void) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_AllocateLePSM();
+  }
+
   bool done = false;
   uint16_t psm = l2cb.le_dyn_psm;
   uint16_t count = 0;
@@ -248,6 +268,10 @@
  *
  ******************************************************************************/
 void L2CA_FreeLePSM(uint16_t psm) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_FreeLePSM(psm);
+  }
+
   L2CAP_TRACE_API("%s: to free psm=%d", __func__, psm);
 
   if ((psm < LE_DYNAMIC_PSM_START) || (psm > LE_DYNAMIC_PSM_END)) {
@@ -275,6 +299,10 @@
  *
  ******************************************************************************/
 uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectReq(psm, p_bd_addr);
+  }
+
   return L2CA_ErtmConnectReq(psm, p_bd_addr, nullptr);
 }
 
@@ -297,6 +325,10 @@
  ******************************************************************************/
 uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
                              tL2CAP_ERTM_INFO* p_ertm_info) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ErtmConnectReq(psm, p_bd_addr, p_ertm_info);
+  }
+
   VLOG(1) << __func__ << "BDA " << p_bd_addr
           << StringPrintf(" PSM: 0x%04x allowed:0x%x preferred:%d", psm,
                           (p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -398,6 +430,10 @@
  *
  ******************************************************************************/
 uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_RegisterLECoc(psm, p_cb_info);
+  }
+
   L2CAP_TRACE_API("%s called for LE PSM: 0x%04x", __func__, psm);
 
   /* Verify that the required callback info has been filled in
@@ -462,6 +498,10 @@
  *
  ******************************************************************************/
 void L2CA_DeregisterLECoc(uint16_t psm) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_DeregisterLECoc(psm);
+  }
+
   L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm);
 
   tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
@@ -508,6 +548,10 @@
  ******************************************************************************/
 uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
                               tL2CAP_LE_CFG_INFO* p_cfg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectLECocReq(psm, p_bd_addr, p_cfg);
+  }
+
   VLOG(1) << __func__ << " BDA: " << p_bd_addr
           << StringPrintf(" PSM: 0x%04x", psm);
 
@@ -596,6 +640,11 @@
 bool L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr, uint8_t id,
                           uint16_t lcid, uint16_t result, uint16_t status,
                           tL2CAP_LE_CFG_INFO* p_cfg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectLECocRsp(p_bd_addr, id, lcid, result,
+                                                 status, p_cfg);
+  }
+
   VLOG(1) << __func__ << " BDA: " << p_bd_addr
           << StringPrintf(" CID: 0x%04x Result: %d Status: %d", lcid, result,
                           status);
@@ -654,6 +703,10 @@
  *
  ******************************************************************************/
 bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetPeerLECocConfig(lcid, peer_cfg);
+  }
+
   L2CAP_TRACE_API("%s CID: 0x%04x", __func__, lcid);
 
   tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
@@ -670,6 +723,10 @@
 
 bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
                                  const tL2CAP_APPL_INFO* callbacks) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetConnectionCallbacks(local_cid, callbacks);
+  }
+
   CHECK(callbacks != NULL);
   CHECK(callbacks->pL2CA_ConnectInd_Cb == NULL);
   CHECK(callbacks->pL2CA_ConnectCfm_Cb != NULL);
@@ -719,6 +776,11 @@
  ******************************************************************************/
 bool L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
                      uint16_t result, uint16_t status) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectRsp(p_bd_addr, id, lcid, result,
+                                            status);
+  }
+
   return L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result, status, NULL);
 }
 
@@ -736,6 +798,11 @@
 bool L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
                          uint16_t result, uint16_t status,
                          tL2CAP_ERTM_INFO* p_ertm_info) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result,
+                                                status, p_ertm_info);
+  }
+
   tL2C_LCB* p_lcb;
   tL2C_CCB* p_ccb;
 
@@ -815,6 +882,10 @@
  *
  ******************************************************************************/
 bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConfigReq(cid, p_cfg);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API(
@@ -864,6 +935,10 @@
  *
  ******************************************************************************/
 bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConfigRsp(cid, p_cfg);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API(
@@ -907,6 +982,10 @@
  *
  ******************************************************************************/
 bool L2CA_DisconnectReq(uint16_t cid) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_DisconnectReq(cid);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API("L2CA_DisconnectReq()  CID: 0x%04x", cid);
@@ -934,6 +1013,10 @@
  *
  ******************************************************************************/
 bool L2CA_DisconnectRsp(uint16_t cid) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_DisconnectRsp(cid);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API("L2CA_DisconnectRsp()  CID: 0x%04x", cid);
@@ -960,6 +1043,10 @@
  *
  ******************************************************************************/
 bool L2CA_Ping(const RawAddress& p_bd_addr, tL2CA_ECHO_RSP_CB* p_callback) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_Ping(p_bd_addr, p_callback);
+  }
+
   tL2C_LCB* p_lcb;
 
   VLOG(1) << __func__ << " BDA: " << p_bd_addr;
@@ -1023,6 +1110,10 @@
  ******************************************************************************/
 bool L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
                tL2CA_ECHO_DATA_CB* p_callback) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_Echo(p_bd_addr, p_data, p_callback);
+  }
+
   tL2C_LCB* p_lcb;
   uint8_t* pp;
 
@@ -1063,6 +1154,10 @@
 }
 
 bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetIdentifiers(lcid, rcid, handle);
+  }
+
   tL2C_CCB* control_block = l2cu_find_ccb_by_cid(NULL, lcid);
   if (!control_block) return false;
 
@@ -1092,6 +1187,10 @@
  *                  set up.
  ******************************************************************************/
 bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetIdleTimeout(cid, timeout, is_global);
+  }
+
   tL2C_CCB* p_ccb;
   tL2C_LCB* p_lcb;
 
@@ -1138,6 +1237,11 @@
  ******************************************************************************/
 bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
                                  tBT_TRANSPORT transport) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(bd_addr, timeout,
+                                                        transport);
+  }
+
   tL2C_LCB* p_lcb;
 
   if (RawAddress::kAny != bd_addr) {
@@ -1198,6 +1302,10 @@
  *
  ******************************************************************************/
 uint8_t L2CA_SetDesireRole(uint8_t new_role) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetDesireRole(new_role);
+  }
+
   L2CAP_TRACE_API("L2CA_SetDesireRole() new:x%x, disallow_switch:%d", new_role,
                   l2cb.disallow_switch);
 
@@ -1228,6 +1336,10 @@
  ******************************************************************************/
 uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
                                const RawAddress& p_bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_LocalLoopbackReq(psm, handle, p_bd_addr);
+  }
+
   tL2C_LCB* p_lcb;
   tL2C_CCB* p_ccb;
   tL2C_RCB* p_rcb;
@@ -1286,6 +1398,10 @@
  *
  ******************************************************************************/
 bool L2CA_SetAclPriority(const RawAddress& bd_addr, uint8_t priority) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetAclPriority(bd_addr, priority);
+  }
+
   VLOG(1) << __func__ << " BDA: " << bd_addr
           << ", priority: " << std::to_string(priority);
   return (l2cu_set_acl_priority(bd_addr, priority, false));
@@ -1303,6 +1419,10 @@
  *
  ******************************************************************************/
 bool L2CA_FlowControl(uint16_t cid, bool data_enabled) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_FlowControl(cid, data_enabled);
+  }
+
   tL2C_CCB* p_ccb;
   bool on_off = !data_enabled;
 
@@ -1346,6 +1466,10 @@
  *
  ******************************************************************************/
 bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type, uint8_t back_track) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SendTestSFrame(cid, sup_type, back_track);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API(
@@ -1382,6 +1506,10 @@
  *
  ******************************************************************************/
 bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetTxPriority(cid, priority);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API("L2CA_SetTxPriority()  CID: 0x%04x, priority:%d", cid,
@@ -1412,6 +1540,10 @@
  ******************************************************************************/
 bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
                           tL2CAP_CHNL_DATA_RATE rx) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetChnlDataRate(cid, tx, rx);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API("L2CA_SetChnlDataRate()  CID: 0x%04x, tx:%d, rx:%d", cid, tx,
@@ -1459,6 +1591,10 @@
  *                  the ACL link.
  ******************************************************************************/
 bool L2CA_SetFlushTimeout(const RawAddress& bd_addr, uint16_t flush_tout) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetFlushTimeout(bd_addr, flush_tout);
+  }
+
   tL2C_LCB* p_lcb;
   uint16_t hci_flush_to;
   uint32_t temp;
@@ -1543,6 +1679,11 @@
  ******************************************************************************/
 bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
                           uint8_t* p_chnl_mask) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetPeerFeatures(bd_addr, p_ext_feat,
+                                                 p_chnl_mask);
+  }
+
   tL2C_LCB* p_lcb;
 
   /* We must already have a link to the remote */
@@ -1576,6 +1717,10 @@
  *
  ******************************************************************************/
 bool L2CA_GetBDAddrbyHandle(uint16_t handle, RawAddress& bd_addr) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetBDAddrbyHandle(handle, bd_addr);
+  }
+
   tL2C_LCB* p_lcb = NULL;
   bool found_dev = false;
 
@@ -1600,6 +1745,10 @@
  *
  ******************************************************************************/
 uint8_t L2CA_GetChnlFcrMode(uint16_t lcid) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetChnlFcrMode(lcid);
+  }
+
   tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
 
   if (p_ccb) {
@@ -1627,6 +1776,10 @@
  ******************************************************************************/
 bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
                                tL2CAP_FIXED_CHNL_REG* p_freg) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_RegisterFixedChannel(fixed_cid, p_freg);
+  }
+
   if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
       (fixed_cid > L2CAP_LAST_FIXED_CHNL)) {
     L2CAP_TRACE_ERROR("L2CA_RegisterFixedChannel()  Invalid CID: 0x%04x",
@@ -1652,12 +1805,21 @@
  *
  ******************************************************************************/
 bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectFixedChnl(fixed_cid, rem_bda);
+  }
+
   uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
   return L2CA_ConnectFixedChnl(fixed_cid, rem_bda, phy);
 }
 
 bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda,
                            uint8_t initiating_phys) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_ConnectFixedChnl(fixed_cid, rem_bda,
+                                                  initiating_phys);
+  }
+
   tL2C_LCB* p_lcb;
   tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
 
@@ -1770,6 +1932,10 @@
  ******************************************************************************/
 uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
                                 BT_HDR* p_buf) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_buf);
+  }
+
   tL2C_LCB* p_lcb;
   tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
 
@@ -1883,6 +2049,10 @@
  *
  ******************************************************************************/
 bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_RemoveFixedChnl(fixed_cid, rem_bda);
+  }
+
   tL2C_LCB* p_lcb;
   tL2C_CCB* p_ccb;
   tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
@@ -1950,6 +2120,11 @@
  ******************************************************************************/
 bool L2CA_SetFixedChannelTout(const RawAddress& rem_bda, uint16_t fixed_cid,
                               uint16_t idle_tout) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetFixedChannelTout(rem_bda, fixed_cid,
+                                                     idle_tout);
+  }
+
   tL2C_LCB* p_lcb;
   tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
 
@@ -1997,6 +2172,11 @@
                            tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
                            tL2CAP_CFG_INFO** pp_peer_cfg,
                            tL2CAP_CH_CFG_BITS* p_peer_cfg_bits) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetCurrentConfig(
+        lcid, pp_our_cfg, p_our_cfg_bits, pp_peer_cfg, p_peer_cfg_bits);
+  }
+
   tL2C_CCB* p_ccb;
 
   L2CAP_TRACE_API("L2CA_GetCurrentConfig()  CID: 0x%04x", lcid);
@@ -2039,6 +2219,10 @@
  ******************************************************************************/
 bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu, uint16_t* rcid,
                               uint16_t* handle) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_GetConnectionConfig(lcid, mtu, rcid, handle);
+  }
+
   tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
   ;
 
@@ -2070,6 +2254,10 @@
  *
  ******************************************************************************/
 bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, const RawAddress& p_bda) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_RegForNoCPEvt(p_cb, p_bda);
+  }
+
   tL2C_LCB* p_lcb;
 
   /* Find the link that is associated with this remote bdaddr */
@@ -2096,6 +2284,10 @@
  *
  ******************************************************************************/
 uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_DataWrite(cid, p_data);
+  }
+
   L2CAP_TRACE_API("L2CA_DataWrite()  CID: 0x%04x  Len: %d", cid, p_data->len);
   return l2c_data_write(cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
 }
@@ -2111,8 +2303,11 @@
  *
  ******************************************************************************/
 bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
-#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_SetChnlFlushability(cid, is_flushable);
+  }
 
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
   tL2C_CCB* p_ccb;
 
   /* Find the channel control block. We don't know the link it is on. */
@@ -2150,6 +2345,10 @@
  *
  ******************************************************************************/
 uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_DataWriteEx(cid, p_data, flags);
+  }
+
   L2CAP_TRACE_API("L2CA_DataWriteEx()  CID: 0x%04x  Len: %d Flags:0x%04X", cid,
                   p_data->len, flags);
   return l2c_data_write(cid, p_data, flags);
@@ -2170,6 +2369,10 @@
  *
  ******************************************************************************/
 uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
+  if (bluetooth::shim::is_gd_shim_enabled()) {
+    return bluetooth::shim::L2CA_FlushChannel(lcid, num_to_flush);
+  }
+
   tL2C_CCB* p_ccb;
   tL2C_LCB* p_lcb;
   uint16_t num_left = 0, num_flushed1 = 0, num_flushed2 = 0;
diff --git a/stack/l2cap/l2c_fcr.cc b/stack/l2cap/l2c_fcr.cc
index 857a0bf..920448b 100644
--- a/stack/l2cap/l2c_fcr.cc
+++ b/stack/l2cap/l2c_fcr.cc
@@ -2163,23 +2163,29 @@
           /* Peer wants ERTM and we support it */
           if ((peer_mode == L2CAP_FCR_ERTM_MODE) &&
               (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
-            L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying ERTM)");
+            L2CAP_TRACE_DEBUG("%s(Trying ERTM)", __func__);
             p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
             can_renegotiate = true;
-          } else /* Falls through */
-
-          case L2CAP_FCR_ERTM_MODE: {
+          } else if (p_ccb->ertm_info.allowed_modes &
+                     L2CAP_FCR_CHAN_OPT_BASIC) {
             /* We can try basic for any other peer mode if we support it */
-            if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
-              L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying Basic)");
-              can_renegotiate = true;
-              p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
-            }
-          } break;
+            L2CAP_TRACE_DEBUG("%s(Trying Basic)", __func__);
+            can_renegotiate = true;
+            p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+          }
+          break;
+        case L2CAP_FCR_ERTM_MODE:
+          /* We can try basic for any other peer mode if we support it */
+          if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
+            L2CAP_TRACE_DEBUG("%s(Trying Basic)", __func__);
+            can_renegotiate = true;
+            p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+          }
+          break;
 
-          default:
-            /* All other scenarios cannot be renegotiated */
-            break;
+        default:
+          /* All other scenarios cannot be renegotiated */
+          break;
       }
 
       if (can_renegotiate) {
diff --git a/stack/l2cap/l2c_int.h b/stack/l2cap/l2c_int.h
index 0b71a19..53b6f32 100644
--- a/stack/l2cap/l2c_int.h
+++ b/stack/l2cap/l2c_int.h
@@ -241,6 +241,7 @@
 
 typedef struct {
   bool in_use;
+  bool log_packets;
   uint16_t psm;
   uint16_t real_psm; /* This may be a dummy RCB for an o/b connection but */
                      /* this is the real PSM that we need to connect to */
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index 8e04c6e..7f6d5b9 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -170,7 +170,12 @@
     p_lcb->link_state = LST_CONNECTING;
   }
 
-  if (p_lcb->link_state != LST_CONNECTING) {
+  if ((p_lcb->link_state == LST_CONNECTED) &&
+      (status == HCI_ERR_CONNECTION_EXISTS)) {
+    L2CAP_TRACE_WARNING("%s: An ACL connection already exists. Handle:%d",
+                        __func__, handle);
+    return (true);
+  } else if (p_lcb->link_state != LST_CONNECTING) {
     L2CAP_TRACE_ERROR("L2CAP got conn_comp in bad state: %d  status: 0x%d",
                       p_lcb->link_state, status);
 
@@ -675,6 +680,8 @@
   uint16_t num_hipri_links = 0;
   uint16_t controller_xmit_quota = l2cb.num_lm_acl_bufs;
   uint16_t high_pri_link_quota = L2CAP_HIGH_PRI_MIN_XMIT_QUOTA_A;
+  bool is_share_buffer =
+      (l2cb.num_lm_ble_bufs == L2C_DEF_NUM_BLE_BUF_SHARED) ? true : false;
 
   /* If no links active, reset buffer quotas and controller buffers */
   if (l2cb.num_links_active == 0) {
@@ -685,7 +692,8 @@
 
   /* First, count the links */
   for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
-    if (p_lcb->in_use) {
+    if (p_lcb->in_use &&
+        (is_share_buffer || p_lcb->transport != BT_TRANSPORT_LE)) {
       if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH)
         num_hipri_links++;
       else
@@ -732,7 +740,8 @@
 
   /* Now, assign the quotas to each link */
   for (yy = 0, p_lcb = &l2cb.lcb_pool[0]; yy < MAX_L2CAP_LINKS; yy++, p_lcb++) {
-    if (p_lcb->in_use) {
+    if (p_lcb->in_use &&
+        (is_share_buffer || p_lcb->transport != BT_TRANSPORT_LE)) {
       if (p_lcb->acl_priority == L2CAP_PRIORITY_HIGH) {
         p_lcb->link_xmit_quota = high_pri_link_quota;
       } else {
diff --git a/stack/l2cap/l2c_main.cc b/stack/l2cap/l2c_main.cc
index 74e7135..128f60e 100644
--- a/stack/l2cap/l2c_main.cc
+++ b/stack/l2cap/l2c_main.cc
@@ -33,6 +33,7 @@
 #include "btm_int.h"
 #include "btu.h"
 #include "device/include/controller.h"
+#include "hci/include/btsnoop.h"
 #include "hcimsgs.h"
 #include "l2c_api.h"
 #include "l2c_int.h"
@@ -79,8 +80,8 @@
 
   uint16_t hci_len;
   STREAM_TO_UINT16(hci_len, p);
-  if (hci_len < L2CAP_PKT_OVERHEAD) {
-    /* Must receive at least the L2CAP length and CID */
+  if (hci_len < L2CAP_PKT_OVERHEAD || hci_len != p_msg->len - 4) {
+    /* Remote-declared packet size must match HCI_ACL size - ACL header (4) */
     L2CAP_TRACE_WARNING("L2CAP - got incorrect hci header");
     osi_free(p_msg);
     return;
@@ -396,6 +397,14 @@
         p_ccb->p_rcb = p_rcb;
         p_ccb->remote_cid = rcid;
 
+        if (p_rcb->psm == BT_PSM_RFCOMM) {
+          btsnoop_get_interface()->add_rfc_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        } else if (p_rcb->log_packets) {
+          btsnoop_get_interface()->whitelist_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        }
+
         l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
         break;
       }
@@ -427,6 +436,15 @@
         else
           l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
 
+        tL2C_RCB* p_rcb = p_ccb->p_rcb;
+        if (p_rcb->psm == BT_PSM_RFCOMM) {
+          btsnoop_get_interface()->add_rfc_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        } else if (p_rcb->log_packets) {
+          btsnoop_get_interface()->whitelist_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        }
+
         break;
       }
 
@@ -763,6 +781,10 @@
 #if (L2CAP_NUM_FIXED_CHNLS > 0)
         if (info_type == L2CAP_FIXED_CHANNELS_INFO_TYPE) {
           if (result == L2CAP_INFO_RESP_RESULT_SUCCESS) {
+            if (p + L2CAP_FIXED_CHNL_ARRAY_SIZE > p_next_cmd) {
+              android_errorWriteLog(0x534e4554, "111215173");
+              return;
+            }
             memcpy(p_lcb->peer_chnl_mask, p, L2CAP_FIXED_CHNL_ARRAY_SIZE);
           }
 
diff --git a/stack/l2cap/l2c_utils.cc b/stack/l2cap/l2c_utils.cc
index 448acaa..593f12f 100644
--- a/stack/l2cap/l2c_utils.cc
+++ b/stack/l2cap/l2c_utils.cc
@@ -33,6 +33,7 @@
 #include "btm_int.h"
 #include "btu.h"
 #include "device/include/controller.h"
+#include "hci/include/btsnoop.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
 #include "l2c_int.h"
@@ -1569,6 +1570,9 @@
   /* If already released, could be race condition */
   if (!p_ccb->in_use) return;
 
+  btsnoop_get_interface()->clear_l2cap_whitelist(
+      p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+
   if (p_rcb && (p_rcb->psm != p_rcb->real_psm)) {
     btm_sec_clr_service_by_psm(p_rcb->psm);
   }
diff --git a/stack/l2cap/l2cap_client.cc b/stack/l2cap/l2cap_client.cc
index 76e4138..b3f3737 100644
--- a/stack/l2cap/l2cap_client.cc
+++ b/stack/l2cap/l2cap_client.cc
@@ -70,8 +70,8 @@
     .pL2CA_ConfigCfm_Cb = config_completed_cb,
     .pL2CA_DisconnectInd_Cb = disconnect_request_cb,
     .pL2CA_DisconnectCfm_Cb = disconnect_completed_cb,
-    .pL2CA_CongestionStatus_Cb = congestion_cb,
     .pL2CA_DataInd_Cb = read_ready_cb,
+    .pL2CA_CongestionStatus_Cb = congestion_cb,
     .pL2CA_TxComplete_Cb = write_completed_cb,
 };
 
diff --git a/stack/rfcomm/rfc_l2cap_if.cc b/stack/rfcomm/rfc_l2cap_if.cc
index 3275d77..3dc4ec2 100644
--- a/stack/rfcomm/rfc_l2cap_if.cc
+++ b/stack/rfcomm/rfc_l2cap_if.cc
@@ -30,6 +30,7 @@
 #include "osi/include/osi.h"
 
 #include "bt_utils.h"
+#include "hci/include/btsnoop.h"
 #include "l2c_api.h"
 #include "l2cdefs.h"
 #include "port_api.h"
@@ -73,7 +74,7 @@
   p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
   p_l2c->pL2CA_TxComplete_Cb = NULL;
 
-  L2CA_Register(BT_PSM_RFCOMM, p_l2c);
+  L2CA_Register(BT_PSM_RFCOMM, p_l2c, true /* enable_snoop */);
 }
 
 /*******************************************************************************
diff --git a/stack/rfcomm/rfc_port_fsm.cc b/stack/rfcomm/rfc_port_fsm.cc
index f486bdd..1b82ddf 100644
--- a/stack/rfcomm/rfc_port_fsm.cc
+++ b/stack/rfcomm/rfc_port_fsm.cc
@@ -34,6 +34,14 @@
 #include "rfc_int.h"
 #include "rfcdefs.h"
 
+#include <set>
+#include "hci/include/btsnoop.h"
+
+static const std::set<uint16_t> uuid_logging_whitelist = {
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+    UUID_SERVCLASS_AG_HANDSFREE,
+};
+
 /******************************************************************************/
 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
 /******************************************************************************/
@@ -206,6 +214,13 @@
     case RFC_EVENT_UA:
       rfc_port_timer_stop(p_port);
       p_port->rfc.state = RFC_STATE_OPENED;
+
+      if (uuid_logging_whitelist.find(p_port->uuid) !=
+          uuid_logging_whitelist.end()) {
+        btsnoop_get_interface()->whitelist_rfc_dlci(p_port->rfc.p_mcb->lcid,
+                                                    p_port->dlci);
+      }
+
       PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
                            p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
       return;
@@ -317,6 +332,12 @@
       } else {
         rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
         p_port->rfc.state = RFC_STATE_OPENED;
+
+        if (uuid_logging_whitelist.find(p_port->uuid) !=
+            uuid_logging_whitelist.end()) {
+          btsnoop_get_interface()->whitelist_rfc_dlci(p_port->rfc.p_mcb->lcid,
+                                                      p_port->dlci);
+        }
       }
       return;
   }
diff --git a/stack/rfcomm/rfc_ts_frames.cc b/stack/rfcomm/rfc_ts_frames.cc
index d253b40..7bc98a2 100644
--- a/stack/rfcomm/rfc_ts_frames.cc
+++ b/stack/rfcomm/rfc_ts_frames.cc
@@ -533,12 +533,21 @@
     return RFC_EVENT_BAD_FRAME;
   }
 
+  if (p_buf->len < (3 + !ead + !eal + 1)) {
+    android_errorWriteLog(0x534e4554, "120255805");
+    RFCOMM_TRACE_ERROR("Bad Length: %d", p_buf->len);
+    return RFC_EVENT_BAD_FRAME;
+  }
   p_buf->len -= (3 + !ead + !eal + 1); /* Additional 1 for FCS */
   p_buf->offset += (3 + !ead + !eal);
 
   /* handle credit if credit based flow control */
   if ((p_mcb->flow == PORT_FC_CREDIT) && (p_frame->type == RFCOMM_UIH) &&
       (p_frame->dlci != RFCOMM_MX_DLCI) && (p_frame->pf == 1)) {
+    if (p_buf->len < sizeof(uint8_t)) {
+      RFCOMM_TRACE_ERROR("Bad Length in flow control: %d", p_buf->len);
+      return RFC_EVENT_BAD_FRAME;
+    }
     p_frame->credit = *p_data++;
     p_buf->len--;
     p_buf->offset++;
diff --git a/stack/sdp/sdp_discovery.cc b/stack/sdp/sdp_discovery.cc
index e7fe979..55259ca 100644
--- a/stack/sdp/sdp_discovery.cc
+++ b/stack/sdp/sdp_discovery.cc
@@ -217,6 +217,12 @@
   p = (uint8_t*)(p_msg + 1) + p_msg->offset;
   uint8_t* p_end = p + p_msg->len;
 
+  if (p_msg->len < 1) {
+    android_errorWriteLog(0x534e4554, "79883568");
+    sdp_disconnect(p_ccb, SDP_GENERIC_ERROR);
+    return;
+  }
+
   BE_STREAM_TO_UINT8(rsp_pdu, p);
 
   p_msg->len--;
@@ -368,11 +374,6 @@
       SDP_TRACE_WARNING("rem_len :%d less than cpy_len:%d", rem_len, cpy_len);
       cpy_len = rem_len;
     }
-    SDP_TRACE_WARNING(
-        "%s: list_len:%d cpy_len:%d p:%p p_ccb:%p p_db:%p raw_size:%d "
-        "raw_used:%d raw_data:%p",
-        __func__, list_len, cpy_len, p, p_ccb, p_ccb->p_db,
-        p_ccb->p_db->raw_size, p_ccb->p_db->raw_used, p_ccb->p_db->raw_data);
     memcpy(&p_ccb->p_db->raw_data[p_ccb->p_db->raw_used], p, cpy_len);
     p_ccb->p_db->raw_used += cpy_len;
   }
@@ -397,6 +398,12 @@
 
   /* If p_reply is NULL, we were called after the records handles were read */
   if (p_reply) {
+    if (p_reply + 4 /* transaction ID and length */ + sizeof(list_byte_count) >
+        p_reply_end) {
+      sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE);
+      return;
+    }
+
     /* Skip transaction ID and length */
     p_reply += 4;
 
diff --git a/stack/sdp/sdp_main.cc b/stack/sdp/sdp_main.cc
index 3df37c5..2211c39 100644
--- a/stack/sdp/sdp_main.cc
+++ b/stack/sdp/sdp_main.cc
@@ -121,7 +121,7 @@
   sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info)) {
+  if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info, true /* enable_snoop */)) {
     SDP_TRACE_ERROR("SDP Registration failed");
   }
 }
diff --git a/stack/smp/smp_act.cc b/stack/smp/smp_act.cc
index db6ed66..21b960b 100644
--- a/stack/smp/smp_act.cc
+++ b/stack/smp/smp_act.cc
@@ -16,6 +16,7 @@
  *
  ******************************************************************************/
 
+#include <cutils/log.h>
 #include <log/log.h>
 #include <string.h>
 #include "btif_common.h"
@@ -488,7 +489,15 @@
  ******************************************************************************/
 void smp_proc_pair_fail(tSMP_CB* p_cb, tSMP_INT_DATA* p_data) {
   SMP_TRACE_DEBUG("%s", __func__);
-  p_cb->status = p_data->status;
+
+  if (p_cb->rcvd_cmd_len < 2) {
+    android_errorWriteLog(0x534e4554, "111214739");
+    SMP_TRACE_WARNING("%s: rcvd_cmd_len %d too short: must be at least 2",
+                      __func__, p_cb->rcvd_cmd_len);
+    p_cb->status = SMP_INVALID_PARAMETERS;
+  } else {
+    p_cb->status = p_data->status;
+  }
 
   /* Cancel pending auth complete timer if set */
   alarm_cancel(p_cb->delayed_auth_timer_ent);
@@ -511,6 +520,14 @@
 
   p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
 
+  if (smp_command_has_invalid_length(p_cb)) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    android_errorWriteLog(0x534e4554, "111850706");
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    return;
+  }
+
   STREAM_TO_UINT8(p_cb->peer_io_caps, p);
   STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
   STREAM_TO_UINT8(p_cb->peer_auth_req, p);
@@ -779,6 +796,14 @@
 
   p_cb->flags |= SMP_PAIR_FLAG_ENC_AFTER_PAIR;
 
+  if (smp_command_has_invalid_length(p_cb)) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    android_errorWriteLog(0x534e4554, "111213909");
+    smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &smp_int_data);
+    return;
+  }
+
   STREAM_TO_UINT8(p_cb->peer_io_caps, p);
   STREAM_TO_UINT8(p_cb->peer_oob_flag, p);
   STREAM_TO_UINT8(p_cb->peer_auth_req, p);
@@ -942,7 +967,7 @@
   STREAM_TO_ARRAY(le_key.penc_key.rand, p, BT_OCTET8_LEN);
 
   /* store the encryption keys from peer device */
-  le_key.lenc_key.ltk = p_cb->ltk;
+  le_key.penc_key.ltk = p_cb->ltk;
   le_key.penc_key.sec_level = p_cb->sec_level;
   le_key.penc_key.key_size = p_cb->loc_enc_size;
 
@@ -977,6 +1002,15 @@
   tBTM_LE_KEY_VALUE pid_key;
 
   SMP_TRACE_DEBUG("%s", __func__);
+
+  if (smp_command_has_invalid_parameters(p_cb)) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    android_errorWriteLog(0x534e4554, "111214770");
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    return;
+  }
+
   smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_ID, true);
 
   STREAM_TO_UINT8(pid_key.pid_key.identity_addr_type, p);
@@ -1000,6 +1034,15 @@
   tBTM_LE_KEY_VALUE le_key;
 
   SMP_TRACE_DEBUG("%s", __func__);
+
+  if (smp_command_has_invalid_parameters(p_cb)) {
+    tSMP_INT_DATA smp_int_data;
+    smp_int_data.status = SMP_INVALID_PARAMETERS;
+    android_errorWriteLog(0x534e4554, "111214470");
+    smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &smp_int_data);
+    return;
+  }
+
   smp_update_key_mask(p_cb, SMP_SEC_KEY_TYPE_CSRK, true);
 
   /* save CSRK to security record */
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index 9886d4f..72fdf55 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -450,6 +450,7 @@
 extern void smp_mask_enc_key(uint8_t loc_enc_size, Octet16* p_data);
 extern void smp_rsp_timeout(void* data);
 extern void smp_delayed_auth_complete_timeout(void* data);
+extern bool smp_command_has_invalid_length(tSMP_CB* p_cb);
 extern bool smp_command_has_invalid_parameters(tSMP_CB* p_cb);
 extern void smp_reject_unexpected_pairing_command(const RawAddress& bd_addr);
 extern tSMP_ASSO_MODEL smp_select_association_model(tSMP_CB* p_cb);
diff --git a/stack/smp/smp_l2c.cc b/stack/smp/smp_l2c.cc
index b6881e6..2daeb21 100644
--- a/stack/smp/smp_l2c.cc
+++ b/stack/smp/smp_l2c.cc
@@ -22,6 +22,7 @@
  *
  ******************************************************************************/
 
+#include <cutils/log.h>
 #include "bt_target.h"
 
 #include <string.h>
@@ -142,6 +143,14 @@
   uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset;
   uint8_t cmd;
 
+  if (p_buf->len < 1) {
+    android_errorWriteLog(0x534e4554, "111215315");
+    SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
+                      __func__, p_buf->len);
+    osi_free(p_buf);
+    return;
+  }
+
   STREAM_TO_UINT8(cmd, p);
 
   SMP_TRACE_EVENT("%s: SMDBG l2c, cmd=0x%x", __func__, cmd);
@@ -286,6 +295,14 @@
   uint8_t cmd;
   SMP_TRACE_EVENT("SMDBG l2c %s", __func__);
 
+  if (p_buf->len < 1) {
+    android_errorWriteLog(0x534e4554, "111215315");
+    SMP_TRACE_WARNING("%s: smp packet length %d too short: must be at least 1",
+                      __func__, p_buf->len);
+    osi_free(p_buf);
+    return;
+  }
+
   STREAM_TO_UINT8(cmd, p);
 
   /* sanity check */
diff --git a/stack/smp/smp_utils.cc b/stack/smp/smp_utils.cc
index f81e21d..b5da5ba 100644
--- a/stack/smp/smp_utils.cc
+++ b/stack/smp/smp_utils.cc
@@ -955,6 +955,33 @@
 
 /*******************************************************************************
  *
+ * Function         smp_command_has_invalid_length
+ *
+ * Description      Checks if the received SMP command has invalid length
+ *                  It returns true if the command has invalid length.
+ *
+ * Returns          true if the command has invalid length, false otherwise.
+ *
+ ******************************************************************************/
+bool smp_command_has_invalid_length(tSMP_CB* p_cb) {
+  uint8_t cmd_code = p_cb->rcvd_cmd_code;
+
+  if ((cmd_code > (SMP_OPCODE_MAX + 1 /* for SMP_OPCODE_PAIR_COMMITM */)) ||
+      (cmd_code < SMP_OPCODE_MIN)) {
+    SMP_TRACE_WARNING("%s: Received command with RESERVED code 0x%02x",
+                      __func__, cmd_code);
+    return true;
+  }
+
+  if (!smp_command_has_valid_fixed_length(p_cb)) {
+    return true;
+  }
+
+  return false;
+}
+
+/*******************************************************************************
+ *
  * Function         smp_command_has_invalid_parameters
  *
  * Description      Checks if the received SMP command has invalid parameters
diff --git a/stack/test/common/mock_btsnoop_module.cc b/stack/test/common/mock_btsnoop_module.cc
new file mode 100644
index 0000000..7a5c5ae
--- /dev/null
+++ b/stack/test/common/mock_btsnoop_module.cc
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ *  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 "hci/include/btsnoop.h"
+
+static void capture(const BT_HDR*, bool) { /* do nothing */
+}
+
+static void whitelist_l2c_channel(uint16_t, uint16_t,
+                                  uint16_t) { /* do nothing */
+}
+
+static void whitelist_rfc_dlci(uint16_t, uint8_t) { /* do nothing */
+}
+
+static void add_rfc_l2c_channel(uint16_t, uint16_t, uint16_t) { /* do nothing */
+}
+
+static void clear_l2cap_whitelist(uint16_t, uint16_t,
+                                  uint16_t) { /* do nothing */
+}
+
+static const btsnoop_t fake_snoop = {capture, whitelist_l2c_channel,
+                                     whitelist_rfc_dlci, add_rfc_l2c_channel,
+                                     clear_l2cap_whitelist};
+
+const btsnoop_t* btsnoop_get_interface() { return &fake_snoop; }
diff --git a/stack/test/common/mock_l2cap_layer.cc b/stack/test/common/mock_l2cap_layer.cc
index 9f08d56..4756f17 100644
--- a/stack/test/common/mock_l2cap_layer.cc
+++ b/stack/test/common/mock_l2cap_layer.cc
@@ -24,9 +24,11 @@
   l2cap_interface = mock_l2cap_interface;
 }
 
-uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
-  VLOG(1) << __func__ << ": psm=" << psm << ", p_cb_info=" << p_cb_info;
-  return l2cap_interface->Register(psm, p_cb_info);
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                       bool enable_snoop) {
+  VLOG(1) << __func__ << ": psm=" << psm << ", p_cb_info=" << p_cb_info
+          << ", enable_snoop=" << enable_snoop;
+  return l2cap_interface->Register(psm, p_cb_info, enable_snoop);
 }
 
 uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& bd_addr) {
diff --git a/stack/test/common/mock_l2cap_layer.h b/stack/test/common/mock_l2cap_layer.h
index 78c8a9c..ade7585 100644
--- a/stack/test/common/mock_l2cap_layer.h
+++ b/stack/test/common/mock_l2cap_layer.h
@@ -26,7 +26,8 @@
 
 class L2capInterface {
  public:
-  virtual uint16_t Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) = 0;
+  virtual uint16_t Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                            bool enable_snoop) = 0;
   virtual uint16_t ConnectRequest(uint16_t psm, const RawAddress& bd_addr) = 0;
   virtual bool ConnectResponse(const RawAddress& bd_addr, uint8_t id,
                                uint16_t lcid, uint16_t result,
@@ -41,7 +42,8 @@
 
 class MockL2capInterface : public L2capInterface {
  public:
-  MOCK_METHOD2(Register, uint16_t(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info));
+  MOCK_METHOD3(Register, uint16_t(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                                  bool enable_snoop));
   MOCK_METHOD2(ConnectRequest,
                uint16_t(uint16_t psm, const RawAddress& bd_addr));
   MOCK_METHOD5(ConnectResponse,
diff --git a/stack/test/rfcomm/stack_rfcomm_test.cc b/stack/test/rfcomm/stack_rfcomm_test.cc
index 3d9da3f..52e1170 100644
--- a/stack/test/rfcomm/stack_rfcomm_test.cc
+++ b/stack/test/rfcomm/stack_rfcomm_test.cc
@@ -453,7 +453,7 @@
         &btm_security_internal_interface_);
     bluetooth::l2cap::SetMockInterface(&l2cap_interface_);
     rfcomm_callback = &rfcomm_callback_;
-    EXPECT_CALL(l2cap_interface_, Register(BT_PSM_RFCOMM, _))
+    EXPECT_CALL(l2cap_interface_, Register(BT_PSM_RFCOMM, _, _))
         .WillOnce(
             DoAll(SaveArgPointee<1>(&l2cap_appl_info_), Return(BT_PSM_RFCOMM)));
     RFCOMM_Init();
diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp
index e312c0e..bd62e50 100644
--- a/test/rootcanal/Android.bp
+++ b/test/rootcanal/Android.bp
@@ -14,7 +14,7 @@
 // limitations under the License.
 
 cc_binary {
-    name: "android.hardware.bluetooth@1.0-service.sim",
+    name: "android.hardware.bluetooth@1.1-service.sim",
     proprietary: true,
     relative_install_path: "hw",
     srcs: [
@@ -25,12 +25,11 @@
     header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "libbase",
         "libchrome",
         "libcutils",
-        "libhwbinder",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -41,6 +40,10 @@
         "-Werror",
         "-DHAS_NO_BDROID_BUILDCFG",
     ],
+    generated_headers: [
+        "RootCanalGeneratedPackets_h",
+        "BluetoothGeneratedPackets_h",
+    ],
     static_libs: [
         "android.hardware.bluetooth-async",
         "android.hardware.bluetooth-hci",
@@ -49,15 +52,16 @@
     ],
     include_dirs: [
         "system/bt",
+        "system/bt/gd",
         "system/bt/hci/include",
         "system/bt/internal_include",
         "system/bt/stack/include",
     ],
-    init_rc: ["android.hardware.bluetooth@1.0-service.sim.rc"],
+    init_rc: ["android.hardware.bluetooth@1.1-service.sim.rc"],
 }
 
 cc_library_shared {
-    name: "android.hardware.bluetooth@1.0-impl-sim",
+    name: "android.hardware.bluetooth@1.1-impl-sim",
     proprietary: true,
     relative_install_path: "hw",
     srcs: [
@@ -67,11 +71,11 @@
     header_libs: ["libbluetooth_headers"],
     shared_libs: [
         "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "libbase",
         "libchrome",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
@@ -81,6 +85,10 @@
         "-Werror",
         "-DHAS_NO_BDROID_BUILDCFG",
     ],
+    generated_headers: [
+        "RootCanalGeneratedPackets_h",
+        "BluetoothGeneratedPackets_h",
+    ],
     static_libs: [
         "android.hardware.bluetooth-async",
         "android.hardware.bluetooth-hci",
@@ -89,6 +97,7 @@
     ],
     include_dirs: [
         "system/bt",
+        "system/bt/gd",
         "system/bt/hci/include",
         "system/bt/internal_include",
         "system/bt/stack/include",
diff --git a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
deleted file mode 100644
index 9d99c8a..0000000
--- a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim
-    class hal
-    user bluetooth
-    group bluetooth
diff --git a/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc
new file mode 100644
index 0000000..2626841
--- /dev/null
+++ b/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc
@@ -0,0 +1,4 @@
+service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.sim
+    class hal
+    user bluetooth
+    group bluetooth
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index 6000d7a..2bebd9a 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -14,23 +14,22 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "android.hardware.bluetooth@1.0.sim"
+#define LOG_TAG "android.hardware.bluetooth@1.1.sim"
 
 #include "bluetooth_hci.h"
 
-#include <base/logging.h>
 #include <cutils/properties.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <string.h>
-#include <utils/Log.h>
 
 #include "hci_internals.h"
+#include "os/log.h"
 
 namespace android {
 namespace hardware {
 namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
 namespace sim {
 
 using android::hardware::hidl_vec;
@@ -54,7 +53,7 @@
   void serviceDied(
       uint64_t /* cookie */,
       const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
-    ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+    LOG_ERROR("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
     has_died_ = true;
     mHci->close();
   }
@@ -72,11 +71,23 @@
 
 BluetoothHci::BluetoothHci() : death_recipient_(new BluetoothDeathRecipient(this)) {}
 
-Return<void> BluetoothHci::initialize(const sp<IBluetoothHciCallbacks>& cb) {
-  ALOGI("%s", __func__);
+Return<void> BluetoothHci::initialize(
+    const sp<V1_0::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, nullptr);
+}
+
+Return<void> BluetoothHci::initialize_1_1(
+    const sp<V1_1::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, cb);
+}
+
+Return<void> BluetoothHci::initialize_impl(
+    const sp<V1_0::IBluetoothHciCallbacks>& cb,
+    const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
+  LOG_INFO("%s", __func__);
 
   if (cb == nullptr) {
-    ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+    LOG_ERROR("cb == nullptr! -> Unable to call initializationComplete(ERR)");
     return Void();
   }
 
@@ -93,7 +104,9 @@
 
   controller_ = std::make_shared<DualModeController>();
 
-  controller_->Initialize({"dmc", "3C:5A:B4:01:02:03"});
+  char mac_property[PROPERTY_VALUE_MAX] = "";
+  property_get("bt.rootcanal_mac_address", mac_property, "3C:5A:B4:01:02:03");
+  controller_->Initialize({"dmc", std::string(mac_property)});
 
   controller_->RegisterEventChannel(
       [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
@@ -125,6 +138,18 @@
         }
       });
 
+  if (cb_1_1 != nullptr) {
+    controller_->RegisterIsoChannel(
+        [this, cb_1_1](std::shared_ptr<std::vector<uint8_t>> packet) {
+          hidl_vec<uint8_t> iso_packet(packet->begin(), packet->end());
+          auto ret = cb_1_1->isoDataReceived(iso_packet);
+          if (!ret.isOk()) {
+            CHECK(death_recipient_->getHasDied())
+                << "Error sending iso callback, but no death notification.";
+          }
+        });
+  }
+
   controller_->RegisterTaskScheduler(
       [this](std::chrono::milliseconds delay, const TaskCallback& task) {
         return async_manager_.ExecAsync(delay, task);
@@ -145,7 +170,7 @@
 
   // Send responses to logcat if the test channel is not configured.
   test_channel_.RegisterSendResponse([](const std::string& response) {
-    ALOGI("No test channel yet: %s", response.c_str());
+    LOG_INFO("No test channel yet: %s", response.c_str());
   });
 
   if (BtTestConsoleEnabled()) {
@@ -160,7 +185,7 @@
   test_channel_.AddDefaults();
 
   // This should be configurable in the future.
-  ALOGI("Adding Beacons so the scan list is not empty.");
+  LOG_INFO("Adding Beacons so the scan list is not empty.");
   test_channel_.Add({"beacon", "be:ac:10:00:00:01", "1000"});
   test_channel_.AddDeviceToPhy({"2", "1"});
   test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
@@ -168,7 +193,7 @@
 
   unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
     if (death_recipient->getHasDied())
-      ALOGI("Skipping unlink call, service died.");
+      LOG_INFO("Skipping unlink call, service died.");
     else {
       auto ret = cb->unlinkToDeath(death_recipient);
       if (!ret.isOk()) {
@@ -178,7 +203,7 @@
     }
   };
 
-  auto init_ret = cb->initializationComplete(Status::SUCCESS);
+  auto init_ret = cb->initializationComplete(V1_0::Status::SUCCESS);
   if (!init_ret.isOk()) {
     CHECK(death_recipient_->getHasDied())
         << "Error sending init callback, but no death notification.";
@@ -187,7 +212,7 @@
 }
 
 Return<void> BluetoothHci::close() {
-  ALOGI("%s", __func__);
+  LOG_INFO("%s", __func__);
   return Void();
 }
 
@@ -218,21 +243,31 @@
   return Void();
 }
 
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& packet) {
+  async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
+    std::shared_ptr<std::vector<uint8_t>> packet_copy =
+        std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>(packet));
+    controller_->HandleIso(packet_copy);
+  });
+  return Void();
+}
+
 void BluetoothHci::SetUpHciServer(int port, const std::function<void(int)>& connection_callback) {
   int socket_fd = remote_hci_transport_.SetUp(port);
 
-  test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+  test_channel_.RegisterSendResponse([](const std::string& response) {
+    LOG_INFO("No HCI Response channel: %s", response.c_str());
+  });
 
   if (socket_fd == -1) {
-    ALOGE("Remote HCI channel SetUp(%d) failed.", port);
+    LOG_ERROR("Remote HCI channel SetUp(%d) failed.", port);
     return;
   }
 
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
     int conn_fd = remote_hci_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching remote HCI channel fd.");
+      LOG_ERROR("Error watching remote HCI channel fd.");
       return;
     }
     int flags = fcntl(conn_fd, F_GETFL, NULL);
@@ -247,18 +282,19 @@
 void BluetoothHci::SetUpLinkLayerServer(int port, const std::function<void(int)>& connection_callback) {
   int socket_fd = remote_link_layer_transport_.SetUp(port);
 
-  test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+  test_channel_.RegisterSendResponse([](const std::string& response) {
+    LOG_INFO("No LinkLayer Response channel: %s", response.c_str());
+  });
 
   if (socket_fd == -1) {
-    ALOGE("Remote LinkLayer channel SetUp(%d) failed.", port);
+    LOG_ERROR("Remote LinkLayer channel SetUp(%d) failed.", port);
     return;
   }
 
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
     int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching remote LinkLayer channel fd.");
+      LOG_ERROR("Error watching remote LinkLayer channel fd.");
       return;
     }
     int flags = fcntl(conn_fd, F_GETFL, NULL);
@@ -272,14 +308,15 @@
 int BluetoothHci::ConnectToRemoteServer(const std::string& server, int port) {
   int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
   if (socket_fd < 1) {
-    ALOGI("socket() call failed: %s", strerror(errno));
+    LOG_INFO("socket() call failed: %s", strerror(errno));
     return -1;
   }
 
   struct hostent* host;
   host = gethostbyname(server.c_str());
   if (host == NULL) {
-    ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+    LOG_INFO("gethostbyname() failed for %s: %s", server.c_str(),
+             strerror(errno));
     return -1;
   }
 
@@ -291,7 +328,8 @@
 
   int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
   if (result < 0) {
-    ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+    LOG_INFO("connect() failed for %s@%d: %s", server.c_str(), port,
+             strerror(errno));
     return -1;
   }
 
@@ -305,22 +343,23 @@
 void BluetoothHci::SetUpTestChannel(int port) {
   int socket_fd = test_channel_transport_.SetUp(port);
 
-  test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+  test_channel_.RegisterSendResponse([](const std::string& response) {
+    LOG_INFO("No test channel: %s", response.c_str());
+  });
 
   if (socket_fd == -1) {
-    ALOGE("Test channel SetUp(%d) failed.", port);
+    LOG_ERROR("Test channel SetUp(%d) failed.", port);
     return;
   }
 
-  ALOGI("Test channel SetUp() successful");
+  LOG_INFO("Test channel SetUp() successful");
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
     int conn_fd = test_channel_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching test channel fd.");
+      LOG_ERROR("Error watching test channel fd.");
       return;
     }
-    ALOGI("Test channel connection accepted.");
+    LOG_INFO("Test channel connection accepted.");
     test_channel_.RegisterSendResponse(
         [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
 
@@ -337,7 +376,7 @@
 }
 
 }  // namespace sim
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
diff --git a/test/rootcanal/bluetooth_hci.h b/test/rootcanal/bluetooth_hci.h
index 96d0ed8..99eda9f 100644
--- a/test/rootcanal/bluetooth_hci.h
+++ b/test/rootcanal/bluetooth_hci.h
@@ -16,7 +16,9 @@
 
 #pragma once
 
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include "os/log.h"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
 
 #include <hidl/MQDescriptor.h>
 
@@ -31,7 +33,7 @@
 namespace android {
 namespace hardware {
 namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
 namespace sim {
 
 class BluetoothDeathRecipient;
@@ -40,7 +42,10 @@
  public:
   BluetoothHci();
 
-  ::android::hardware::Return<void> initialize(const sp<IBluetoothHciCallbacks>& cb) override;
+  ::android::hardware::Return<void> initialize(
+      const sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+  ::android::hardware::Return<void> initialize_1_1(
+      const sp<V1_1::IBluetoothHciCallbacks>& cb) override;
 
   ::android::hardware::Return<void> sendHciCommand(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
 
@@ -48,6 +53,9 @@
 
   ::android::hardware::Return<void> sendScoData(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
 
+  ::android::hardware::Return<void> sendIsoData(
+      const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
   ::android::hardware::Return<void> close() override;
 
   static void OnPacketReady();
@@ -55,6 +63,10 @@
   static BluetoothHci* get();
 
  private:
+  ::android::hardware::Return<void> initialize_impl(
+      const sp<V1_0::IBluetoothHciCallbacks>& cb,
+      const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1);
+
   sp<BluetoothDeathRecipient> death_recipient_;
 
   std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
@@ -94,7 +106,7 @@
 extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
 
 }  // namespace sim
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
diff --git a/test/rootcanal/service.cc b/test/rootcanal/service.cc
index 64fa9c7..7856dcf 100644
--- a/test/rootcanal/service.cc
+++ b/test/rootcanal/service.cc
@@ -14,20 +14,21 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "android.hardware.bluetooth@1.0-service.sim"
+#define LOG_TAG "android.hardware.bluetooth@1.1-service.sim"
 
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include "os/log.h"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
-#include <utils/Log.h>
 
 #include "bluetooth_hci.h"
 
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
 using ::android::hardware::joinRpcThreadpool;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::sim::BluetoothHci;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::sim::BluetoothHci;
 
 int main(int /* argc */, char** /* argv */) {
   sp<IBluetoothHci> bluetooth = new BluetoothHci;
@@ -36,5 +37,5 @@
   if (status == android::OK)
     joinRpcThreadpool();
   else
-    ALOGE("Could not register as a service!");
+    LOG_ERROR("Could not register as a service!");
 }
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index 85b46fa..1d919ed 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -15,6 +15,8 @@
     shared_libs: [
         "liblog",
         "libcutils",
+        "libbinder",
+        "libutils",
     ],
     static_libs: [
         "libbtcore",
@@ -40,6 +42,8 @@
     shared_libs: [
         "liblog",
         "libcutils",
+        "libbinder",
+        "libutils",
     ],
     static_libs: [
         "libbtcore",
diff --git a/test/suite/adapter/adapter_unittest.cc b/test/suite/adapter/adapter_unittest.cc
index 24ca3e5..7a26e28 100644
--- a/test/suite/adapter/adapter_unittest.cc
+++ b/test/suite/adapter/adapter_unittest.cc
@@ -35,7 +35,7 @@
   EXPECT_EQ(GetState(), BT_STATE_OFF)
       << "Test should be run with Adapter disabled";
 
-  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
 
@@ -49,7 +49,7 @@
       << "Test should be run with Adapter disabled";
 
   for (int i = 0; i < kTestRepeatCount; ++i) {
-    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+    EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
     semaphore_wait(adapter_state_changed_callback_sem_);
     EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
 
@@ -62,7 +62,7 @@
 TEST_F(BluetoothTest, AdapterSetGetName) {
   bt_property_t* new_name = property_new_name("BluetoothTestName1");
 
-  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
       << "Test should be run with Adapter enabled";
@@ -114,7 +114,7 @@
 }
 
 TEST_F(BluetoothTest, AdapterStartDiscovery) {
-  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
       << "Test should be run with Adapter enabled";
@@ -130,7 +130,7 @@
 }
 
 TEST_F(BluetoothTest, AdapterCancelDiscovery) {
-  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
       << "Test should be run with Adapter enabled";
@@ -155,7 +155,7 @@
   RawAddress bdaddr = {{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}};
 
   for (int i = 0; i < kTestRepeatCount; ++i) {
-    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+    EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
     semaphore_wait(adapter_state_changed_callback_sem_);
     EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
 
@@ -179,8 +179,8 @@
   ASSERT_TRUE(bt_callbacks != nullptr);
 
   for (int i = 0; i < kTestRepeatCount; ++i) {
-    bt_interface()->init(bt_callbacks);
-    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+    bt_interface()->init(bt_callbacks, false, false);
+    EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
     semaphore_wait(adapter_state_changed_callback_sem_);
     EXPECT_EQ(GetState(), BT_STATE_ON) << "Adapter did not turn on.";
 
diff --git a/test/suite/adapter/bluetooth_test.cc b/test/suite/adapter/bluetooth_test.cc
index 02132f1..626ac42 100644
--- a/test/suite/adapter/bluetooth_test.cc
+++ b/test/suite/adapter/bluetooth_test.cc
@@ -17,6 +17,8 @@
  ******************************************************************************/
 
 #include "adapter/bluetooth_test.h"
+#include <binder/ProcessState.h>
+#include <stdio.h>
 #include <mutex>
 #include "btcore/include/property.h"
 
@@ -31,6 +33,7 @@
 namespace bttest {
 
 void BluetoothTest::SetUp() {
+  android::ProcessState::self()->startThreadPool();
   bt_interface_ = nullptr;
   state_ = BT_STATE_OFF;
   properties_changed_count_ = 0;
@@ -46,6 +49,9 @@
   adapter_state_changed_callback_sem_ = semaphore_new(0);
   discovery_state_changed_callback_sem_ = semaphore_new(0);
 
+  remove("/data/misc/bluedroid/bt_config.conf.encrypted-checksum");
+  remove("/data/misc/bluedroid/bt_config.bak.encrypted-checksum");
+
   bluetooth::hal::BluetoothInterface::Initialize();
   ASSERT_TRUE(bluetooth::hal::BluetoothInterface::IsInitialized());
   auto bt_hal_interface = bluetooth::hal::BluetoothInterface::Get();
diff --git a/test/suite/gatt/gatt_test.cc b/test/suite/gatt/gatt_test.cc
index e3546d3..8c8f1ab 100644
--- a/test/suite/gatt/gatt_test.cc
+++ b/test/suite/gatt/gatt_test.cc
@@ -33,7 +33,7 @@
   status_ = 0;
 
   BluetoothTest::SetUp();
-  ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  ASSERT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_TRUE(GetState() == BT_STATE_ON);
 
diff --git a/test/suite/gatt/gatt_unittest.cc b/test/suite/gatt/gatt_unittest.cc
index 26fd850..b02c96a 100644
--- a/test/suite/gatt/gatt_unittest.cc
+++ b/test/suite/gatt/gatt_unittest.cc
@@ -69,12 +69,21 @@
   int server_if = server_interface_id();
 
   std::vector<btgatt_db_element_t> service = {
-      {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = srvc_uuid},
-      {.type = BTGATT_DB_CHARACTERISTIC,
-       .uuid = char_uuid,
-       .properties = 0x10 /* notification */,
-       .permissions = 0x01 /* read only */},
-      {.type = BTGATT_DB_DESCRIPTOR, .uuid = desc_uuid, .permissions = 0x01}};
+      {
+          .uuid = srvc_uuid,
+          .type = BTGATT_DB_PRIMARY_SERVICE,
+      },
+      {
+          .uuid = char_uuid,
+          .type = BTGATT_DB_CHARACTERISTIC,
+          .properties = 0x10,  /* notification */
+          .permissions = 0x01, /* read only */
+      },
+      {
+          .uuid = desc_uuid,
+          .type = BTGATT_DB_DESCRIPTOR,
+          .permissions = 0x01,
+      }};
 
   gatt_server_interface()->add_service(server_if, service);
   semaphore_wait(service_added_callback_sem_);
diff --git a/test/suite/rfcomm/rfcomm_test.cc b/test/suite/rfcomm/rfcomm_test.cc
index 01d9fed..d5baf35 100644
--- a/test/suite/rfcomm/rfcomm_test.cc
+++ b/test/suite/rfcomm/rfcomm_test.cc
@@ -28,7 +28,7 @@
 void RFCommTest::SetUp() {
   BluetoothTest::SetUp();
 
-  ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
+  ASSERT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   ASSERT_TRUE(GetState() == BT_STATE_ON);
   socket_interface_ =
diff --git a/tools/hci/main.c b/tools/hci/main.c
index c167886..093af6b 100644
--- a/tools/hci/main.c
+++ b/tools/hci/main.c
@@ -15,6 +15,7 @@
   HCI_PACKET_ACL_DATA = 2,
   HCI_PACKET_SCO_DATA = 3,
   HCI_PACKET_EVENT = 4,
+  HCI_PACKET_ISO = 5,
 } hci_packet_t;
 
 typedef struct {
diff --git a/tools/scripts/btsnoop_live.py b/tools/scripts/btsnoop_live.py
new file mode 100644
index 0000000..4e145ff
--- /dev/null
+++ b/tools/scripts/btsnoop_live.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+###############################################################################################################
+#
+#  Copyright (C) 2019 Motorola Mobility LLC
+#
+#  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+#  the following conditions are met:
+#
+#  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
+#     following disclaimer.
+#
+#  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+#     the following disclaimer in the documentation and/or other materials provided with the distribution.
+#
+#  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
+#     promote products derived from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+#  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+#  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+#  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+#  POSSIBILITY OF SUCH DAMAGE.
+#
+###############################################################################################################
+###############################################################################################################
+#
+#                             Bluetooth Virtual Sniffing for Android
+#
+#  This script supports Bluetooth Virtual Sniffing via Live Import Feature of Frontline Bluetooth Sniffer(FTS)
+#
+#  It extracts the HCI packets from Snoop logs and redirect it to FTS for live HCI sniffing.
+#
+#  It uses liveimport.ini and LiveImportAPI.dll from FTS path to communicate with FTS sniffer software.
+#
+#  It works on both Windows and Ubuntu. For Ubuntu, both FTS and Python should be installed on Wine.
+#
+#  FTS_INI_PATH & FTS_DLL_PATH should be set to absolute path of liveimport.ini and LiveImportAPI.dll of FTS
+#
+#  Example below - This may change per machine per FTS version in Windows vs Ubuntu (Wine), set accordingly.
+#  For Windows
+#    FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\'
+#    FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+#  For Ubuntu - FTS path recognized by Wine (not Ubuntu path)
+#    FTS_INI_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\'
+#    FTS_DLL_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+###############################################################################################################
+
+import os
+import platform
+import socket
+import struct
+import subprocess
+import sys
+import time
+if sys.version_info[0] >= 3:
+    import configparser
+else:
+    import ConfigParser as configparser
+
+from calendar import timegm
+from ctypes import byref, c_bool, c_longlong, CDLL
+from _ctypes import FreeLibrary
+from datetime import datetime
+
+
+# Update below to right path corresponding to your machine, FTS version and OS used.
+FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\'
+FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\Executables\\Core\\'
+
+
+iniName = 'liveimport.ini'
+if (platform.architecture()[0] == '32bit'):
+    dllName = 'LiveImportAPI.dll'
+else:
+    dllName = 'LiveImportAPI_x64.dll'
+
+launchFtsCmd = '\"'+FTS_DLL_PATH + 'fts.exe\"' + ' \"/ComProbe Protocol Analysis System=Generic\"' + ' \"/oemkey=Virtual\"'
+
+# Unix Epoch delta since 01/01/1970
+FILETIME_EPOCH_DELTA = 116444736000000000
+HUNDREDS_OF_NANOSECONDS = 10000000
+
+HOST = 'localhost'
+PORT = 8872
+SNOOP_ID = 16
+SNOOP_HDR = 24
+
+
+def get_file_time():
+    """
+    Obtain current time in file time format for display
+    """
+    date_time = datetime.now()
+    file_time = FILETIME_EPOCH_DELTA + (timegm(date_time.timetuple()) * HUNDREDS_OF_NANOSECONDS)
+    file_time = file_time + (date_time.microsecond * 10)
+    return file_time
+
+
+def get_connection_string():
+    """
+    Read ConnectionString from liveimport.ini
+    """
+    config = configparser.ConfigParser()
+    config.read(FTS_INI_PATH + iniName)
+    try:
+        conn_str = config.get('General', 'ConnectionString')
+    except (configparser.NoSectionError, configparser.NoOptionError):
+        return None
+
+    return conn_str
+
+
+def get_configuration_string():
+    """
+    Read Configuration string from liveimport.ini
+    """
+    config_str = ''
+    config = configparser.ConfigParser()
+    config.read(FTS_INI_PATH + iniName)
+    try:
+        config_items = config.items('Configuration')
+    except (configparser.NoSectionError, configparser.NoOptionError):
+        return None
+
+    if config_items is not None:
+        for item in config_items:
+            key, value = item
+            config_str += ("%s=%s\n" % (key, value))
+        return config_str
+    else:
+        return None
+
+def check_live_import_connection(live_import):
+    """
+    Launch FTS app in Virtual Sniffing Mode
+    Check if FTS App is ready to start receiving the data.
+    If not, wait until 1 min and exit if FTS didn't start.
+    """
+    is_connection_running = c_bool()
+    count = 0
+
+    status = live_import.IsAppReady(byref(is_connection_running))
+    if (is_connection_running.value == True):
+        print ("FTS is already launched, Start capture if not already started")
+        return True
+
+    print("Launching FTS Virtual Sniffing")
+    try:
+        ftsProcess = subprocess.Popen((launchFtsCmd), stdout=subprocess.PIPE)
+    except:
+        print("Error in Launching FTS.. exiting")
+        return False
+
+    while (is_connection_running.value == False and count < 12):
+        status = live_import.IsAppReady(byref(is_connection_running))
+        if (status < 0):
+            print("Live Import Internal Error %d" %(status))
+            return False
+        if (is_connection_running.value == False):
+            print("Waiting for 5 sec.. Open FTS Virtual Sniffing")
+            time.sleep(5)
+            count += 1
+    if (is_connection_running.value == True):
+        print ("FTS is ready to receive the data, Start capture now")
+        return True
+    else:
+        print("FTS Virtual Sniffing didn't start until 1 min.. exiting")
+        return False
+
+
+def init_live_import(conn_str, config_str):
+    """
+    Load DLL and Initialize the LiveImport module for FTS.
+    """
+    success = c_bool()
+    try:
+        live_import = CDLL(FTS_DLL_PATH + dllName)
+    except:
+        return None
+
+    if live_import is None:
+        print("Error: Path to LiveImportAPI.dll is incorrect.. exiting");
+        return None
+
+    print(dllName + " loaded successfully")
+    result = live_import.InitializeLiveImport(conn_str.encode('ascii', 'ignore'),
+                                              config_str.encode('ascii', 'ignore'),
+                                              byref(success))
+    if (result < 0):
+        print("Live Import Init failed")
+        return None
+    else:
+        print("Live Import Init success")
+        return live_import
+
+
+def release_live_import(live_import):
+    """
+    Cleanup and exit live import module.
+    """
+    if live_import is not None:
+        live_import.ReleaseLiveImport()
+        FreeLibrary(live_import._handle)
+
+
+def main():
+
+    print("Bluetooth Virtual Sniffing for Fluoride")
+    connection_str = get_connection_string()
+    if connection_str is None:
+        print("Error: path to liveimport.ini is incorrect.. exiting")
+        exit(0)
+
+    configuration_str = get_configuration_string()
+    if configuration_str is None:
+        print("Error: path to liveimport.ini is incorrect.. exiting")
+        exit(0)
+
+    live_import = init_live_import(connection_str, configuration_str)
+    if live_import is None:
+        print("Error: Path to LiveImportAPI.dll is incorrect.. exiting")
+        exit(0)
+
+    if (check_live_import_connection(live_import) == False):
+        release_live_import(live_import)
+        exit(0)
+
+    # Wait until the forward socket is ready
+    print("Waiting until adb is ready")
+    os.system('adb wait-for-device forward tcp:8872 tcp:8872')
+
+    btsnoop_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    btsnoop_sock.connect((HOST, PORT))
+    snoop_id = btsnoop_sock.recv(SNOOP_ID)
+    if not snoop_id.startswith(b"btsnoop"):
+        print("Error: Snoop ID wasn't received.. exiting")
+        release_live_import(live_import)
+        exit(0)
+
+    while True:
+        try:
+            snoop_hdr  = btsnoop_sock.recv(SNOOP_HDR)
+            if snoop_hdr is not None:
+                try:
+                    olen, ilen, flags = struct.unpack(">LLL", snoop_hdr[0:12])
+                except struct.error:
+                    print("Error: Invalid data", repr(snoop_hdr))
+                    continue
+
+                file_time = get_file_time()
+                timestamp = c_longlong(file_time)
+
+                snoop_data = b''
+                while (len(snoop_data) < olen):
+                    data_frag = btsnoop_sock.recv(olen - len(snoop_data))
+                    if data_frag is not None:
+                        snoop_data += data_frag
+
+                print ("Bytes received %d Olen %d ilen %d flags %d" % (len(snoop_data), olen, ilen, flags))
+                packet_type = struct.unpack(">B", snoop_data[0:1])[0]
+                if packet_type == 1:
+                    drf = 1
+                    isend = 0
+                elif packet_type == 2:
+                    drf = 2
+                    if (flags & 0x01):
+                        isend = 1
+                    else:
+                        isend = 0
+                elif packet_type == 3:
+                    drf = 4
+                    if (flags & 0x01):
+                        isend = 1
+                    else:
+                        isend = 0
+                elif packet_type == 4:
+                    drf = 8
+                    isend = 1
+
+                result = live_import.SendFrame(olen-1, olen-1, snoop_data[1:olen], drf, isend, timestamp)
+                if (result < 0):
+                    print("Send frame failed")
+        except KeyboardInterrupt:
+            print("Cleanup and exit")
+            release_live_import(live_import)
+            btsnoop_sock.close()
+            exit(0)
+
+
+if __name__ == '__main__':
+    main()
+
diff --git a/types/class_of_device.h b/types/class_of_device.h
index 8c2ab37..4c37ebf 100644
--- a/types/class_of_device.h
+++ b/types/class_of_device.h
@@ -20,6 +20,9 @@
 
 #include <string>
 
+namespace bluetooth {
+namespace types {
+
 /** Bluetooth Class of Device */
 class ClassOfDevice final {
  public:
@@ -52,3 +55,8 @@
   os << c.ToString();
   return os;
 }
+
+}  // namespace types
+}  // namespace bluetooth
+
+using ::bluetooth::types::ClassOfDevice;  // TODO, remove
\ No newline at end of file
diff --git a/udrv/ulinux/uipc.cc b/udrv/ulinux/uipc.cc
index e2f2950..24fa711 100644
--- a/udrv/ulinux/uipc.cc
+++ b/udrv/ulinux/uipc.cc
@@ -621,15 +621,15 @@
 uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id,
                    UNUSED_ATTR uint16_t* p_msg_evt, uint8_t* p_buf,
                    uint32_t len) {
-  int n_read = 0;
-  int fd = uipc.ch[ch_id].fd;
-  struct pollfd pfd;
-
   if (ch_id >= UIPC_CH_NUM) {
     BTIF_TRACE_ERROR("UIPC_Read : invalid ch id %d", ch_id);
     return 0;
   }
 
+  int n_read = 0;
+  int fd = uipc.ch[ch_id].fd;
+  struct pollfd pfd;
+
   if (fd == UIPC_DISCONNECTED) {
     BTIF_TRACE_ERROR("UIPC_Read : channel %d closed", ch_id);
     return 0;
diff --git a/vendor_libs/linux/interface/Android.bp b/vendor_libs/linux/interface/Android.bp
index c4b6041..e7d161e 100644
--- a/vendor_libs/linux/interface/Android.bp
+++ b/vendor_libs/linux/interface/Android.bp
@@ -14,7 +14,7 @@
 // limitations under the License.
 
 cc_binary {
-    name: "android.hardware.bluetooth@1.0-service.btlinux",
+    name: "android.hardware.bluetooth@1.1-service.btlinux",
     proprietary: true,
     relative_install_path: "hw",
     srcs: [
@@ -30,16 +30,15 @@
     ],
     header_libs: ["libbluetooth_headers"],
     shared_libs: [
-        "android.hardware.bluetooth@1.0",
+        "android.hardware.bluetooth@1.1",
         "libbase",
         "libcutils",
         "libhidlbase",
-        "libhidltransport",
         "liblog",
         "libutils",
     ],
     conlyflags: [
         "-std=c99",
     ],
-    init_rc: ["android.hardware.bluetooth@1.0-service.btlinux.rc"],
+    init_rc: ["android.hardware.bluetooth@1.1-service.btlinux.rc"],
 }
diff --git a/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc b/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc
deleted file mode 100644
index 36fbc2c..0000000
--- a/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service btlinux-1.0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.btlinux
-    class hal
-    user bluetooth
-    group bluetooth net_admin net_bt_admin
-    capabilities NET_ADMIN
diff --git a/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc b/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc
new file mode 100644
index 0000000..cb03de2
--- /dev/null
+++ b/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc
@@ -0,0 +1,5 @@
+service btlinux-1.1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.btlinux
+    class hal
+    user bluetooth
+    group bluetooth net_admin net_bt_admin
+    capabilities NET_ADMIN
diff --git a/vendor_libs/linux/interface/bluetooth_hci.cc b/vendor_libs/linux/interface/bluetooth_hci.cc
index 5ed2ff6..bd987d8 100644
--- a/vendor_libs/linux/interface/bluetooth_hci.cc
+++ b/vendor_libs/linux/interface/bluetooth_hci.cc
@@ -14,7 +14,7 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "android.hardware.bluetooth@1.0-btlinux"
+#define LOG_TAG "android.hardware.bluetooth@1.1-btlinux"
 #include <errno.h>
 #include <fcntl.h>
 #include <poll.h>
@@ -66,7 +66,7 @@
 namespace android {
 namespace hardware {
 namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
 namespace btlinux {
 
 int BluetoothHci::openBtHci() {
@@ -264,7 +264,18 @@
     : death_recipient_(new BluetoothDeathRecipient(this)) {}
 
 Return<void> BluetoothHci::initialize(
-    const ::android::sp<IBluetoothHciCallbacks>& cb) {
+    const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, nullptr);
+}
+
+Return<void> BluetoothHci::initialize_1_1(
+    const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) {
+  return initialize_impl(cb, cb);
+}
+
+Return<void> BluetoothHci::initialize_impl(
+    const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb,
+    const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
   ALOGI("BluetoothHci::initialize()");
   if (cb == nullptr) {
     ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
@@ -275,7 +286,7 @@
   cb->linkToDeath(death_recipient_, 0);
   int hci_fd = openBtHci();
   auto hidl_status = cb->initializationComplete(
-          hci_fd > 0 ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
+      hci_fd > 0 ? V1_0::Status::SUCCESS : V1_0::Status::INITIALIZATION_ERROR);
   if (!hidl_status.isOk()) {
       ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
   }
@@ -283,7 +294,10 @@
       hci_fd,
       [cb](const hidl_vec<uint8_t>& packet) { cb->hciEventReceived(packet); },
       [cb](const hidl_vec<uint8_t>& packet) { cb->aclDataReceived(packet); },
-      [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); });
+      [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); },
+      [cb_1_1](const hidl_vec<uint8_t>& packet) {
+        cb_1_1->isoDataReceived(packet);
+      });
 
   fd_watcher_.WatchFdForNonBlockingReads(
           hci_fd, [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
@@ -327,6 +341,11 @@
   return Void();
 }
 
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& data) {
+  sendDataToController(HCI_DATA_TYPE_ISO, data);
+  return Void();
+}
+
 void BluetoothHci::sendDataToController(const uint8_t type,
                                         const hidl_vec<uint8_t>& data) {
   hci_handle_->Send(type, data.data(), data.size());
@@ -337,7 +356,7 @@
 }
 
 }  // namespace btlinux
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
diff --git a/vendor_libs/linux/interface/bluetooth_hci.h b/vendor_libs/linux/interface/bluetooth_hci.h
index 5dc1c0a..095c10c 100644
--- a/vendor_libs/linux/interface/bluetooth_hci.h
+++ b/vendor_libs/linux/interface/bluetooth_hci.h
@@ -14,10 +14,11 @@
 // limitations under the License.
 //
 
-#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
-#define HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+#define HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
 
 #include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
 
 #include <hidl/MQDescriptor.h>
 
@@ -28,7 +29,7 @@
 namespace android {
 namespace hardware {
 namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
 namespace btlinux {
 
 using ::android::hardware::Return;
@@ -40,13 +41,20 @@
  public:
   BluetoothHci();
   Return<void> initialize(
-      const ::android::sp<IBluetoothHciCallbacks>& cb) override;
+      const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+  Return<void> initialize_1_1(
+      const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) override;
   Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override;
   Return<void> sendAclData(const hidl_vec<uint8_t>& data) override;
   Return<void> sendScoData(const hidl_vec<uint8_t>& data) override;
+  Return<void> sendIsoData(const hidl_vec<uint8_t>& data) override;
   Return<void> close() override;
 
  private:
+  Return<void> initialize_impl(
+      const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb,
+      const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb_1_1);
+
   async::AsyncFdWatcher fd_watcher_;
   hci::H4Protocol* hci_handle_;
   int bt_soc_fd_;
@@ -55,6 +63,7 @@
   const uint8_t HCI_DATA_TYPE_COMMAND = 1;
   const uint8_t HCI_DATA_TYPE_ACL = 2;
   const uint8_t HCI_DATA_TYPE_SCO = 3;
+  const uint8_t HCI_DATA_TYPE_ISO = 5;
 
   int waitHciDev(int hci_interface);
   int findRfKill(void);
@@ -70,9 +79,9 @@
 extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
 
 }  // namespace btlinux
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
 
-#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+#endif  // HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
diff --git a/vendor_libs/linux/interface/h4_protocol.cc b/vendor_libs/linux/interface/h4_protocol.cc
index e7acff4..e7c0f62 100644
--- a/vendor_libs/linux/interface/h4_protocol.cc
+++ b/vendor_libs/linux/interface/h4_protocol.cc
@@ -67,6 +67,9 @@
     case HCI_PACKET_TYPE_SCO_DATA:
       sco_cb_(hci_packetizer_.GetPacket());
       break;
+    case HCI_PACKET_TYPE_ISO_DATA:
+      iso_cb_(hci_packetizer_.GetPacket());
+      break;
     default: {
       bool bad_packet_type = true;
       CHECK(!bad_packet_type);
diff --git a/vendor_libs/linux/interface/h4_protocol.h b/vendor_libs/linux/interface/h4_protocol.h
index 612b0db..92d6698 100644
--- a/vendor_libs/linux/interface/h4_protocol.h
+++ b/vendor_libs/linux/interface/h4_protocol.h
@@ -33,11 +33,12 @@
 class H4Protocol {
  public:
   H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
-             PacketReadCallback sco_cb)
+             PacketReadCallback sco_cb, PacketReadCallback iso_cb)
       : uart_fd_(fd),
         event_cb_(event_cb),
         acl_cb_(acl_cb),
         sco_cb_(sco_cb),
+        iso_cb_(iso_cb),
         hci_packetizer_([this]() { OnPacketReady(); }) {}
 
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
@@ -52,6 +53,7 @@
   PacketReadCallback event_cb_;
   PacketReadCallback acl_cb_;
   PacketReadCallback sco_cb_;
+  PacketReadCallback iso_cb_;
 
   HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
   HciPacketizer hci_packetizer_;
diff --git a/vendor_libs/linux/interface/hci_internals.h b/vendor_libs/linux/interface/hci_internals.h
index 1e1f300..24e944f 100644
--- a/vendor_libs/linux/interface/hci_internals.h
+++ b/vendor_libs/linux/interface/hci_internals.h
@@ -24,7 +24,8 @@
   HCI_PACKET_TYPE_COMMAND = 1,
   HCI_PACKET_TYPE_ACL_DATA = 2,
   HCI_PACKET_TYPE_SCO_DATA = 3,
-  HCI_PACKET_TYPE_EVENT = 4
+  HCI_PACKET_TYPE_EVENT = 4,
+  HCI_PACKET_TYPE_ISO_DATA = 5,
 };
 
 // 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
diff --git a/vendor_libs/linux/interface/service.cc b/vendor_libs/linux/interface/service.cc
index fac9ce0..4efd5e7 100644
--- a/vendor_libs/linux/interface/service.cc
+++ b/vendor_libs/linux/interface/service.cc
@@ -14,20 +14,20 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "android.hardware.bluetooth@1.0-service.btlinux"
+#define LOG_TAG "android.hardware.bluetooth@1.1-service.btlinux"
 
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
 #include <utils/Log.h>
 
 #include "bluetooth_hci.h"
 
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::btlinux::BluetoothHci;
-using ::android::hardware::joinRpcThreadpool;
 using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::btlinux::BluetoothHci;
 
 int main(int /* argc */, char** /* argv */) {
   sp<IBluetoothHci> bluetooth = new BluetoothHci;
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index aded1c3..7d20b25 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -35,6 +35,8 @@
         "model/setup/test_channel_transport.cc",
         "model/setup/test_command_handler.cc",
         "model/setup/test_model.cc",
+        ":BluetoothPacketSources",
+        ":BluetoothHciClassSources",
     ],
     cflags: [
         "-fvisibility=hidden",
@@ -47,15 +49,13 @@
         "include",
         ".",
     ],
-    header_libs: [
-        "libbluetooth_headers",
+    generated_headers: [
+        "RootCanalGeneratedPackets_h",
+        "BluetoothGeneratedPackets_h",
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/utils/include",
-        "system/bt/hci/include",
-        "system/bt/internal_include",
-        "system/bt/stack/include",
+        "system/bt/gd",
     ],
     shared_libs: [
         "libbase",
@@ -90,9 +90,7 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/utils/include",
-        "system/bt/hci/include",
-        "system/bt/stack/include",
+        "system/bt/gd",
     ],
     shared_libs: [
         "liblog",
@@ -126,9 +124,11 @@
     ],
     include_dirs: [
         "system/bt",
-        "system/bt/utils/include",
-        "system/bt/hci/include",
-        "system/bt/stack/include",
+        "system/bt/gd",
+    ],
+    generated_headers: [
+        "RootCanalGeneratedPackets_h",
+        "BluetoothGeneratedPackets_h",
     ],
     shared_libs: [
         "liblog",
@@ -138,3 +138,17 @@
         "libbt-rootcanal",
     ],
 }
+
+genrule {
+    name: "RootCanalGeneratedPackets_h",
+    tools: [
+        "bluetooth_packetgen",
+    ],
+    cmd: "$(location bluetooth_packetgen) --root_namespace=model --include=system/bt/vendor_libs/test_vendor_lib --out=$(genDir) $(in)",
+    srcs: [
+        "packets/link_layer_packets.pdl",
+    ],
+    out: [
+        "packets/link_layer_packets.h",
+    ],
+}
diff --git a/vendor_libs/test_vendor_lib/data/controller_properties.json b/vendor_libs/test_vendor_lib/data/controller_properties.json
index 32adc52..814efd3 100644
--- a/vendor_libs/test_vendor_lib/data/controller_properties.json
+++ b/vendor_libs/test_vendor_lib/data/controller_properties.json
@@ -1,5 +1,6 @@
 {
   "AclDataPacketSize": "1024",
+  "EncryptionKeySize": "10",
   "ScoDataPacketSize": "255",
   "NumAclDataPackets": "10",
   "NumScoDataPackets": "10",
diff --git a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
index 5432292..95bbfd3 100644
--- a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
+++ b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
@@ -14,15 +14,11 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "root_canal"
-
 #include "test_environment.h"
 
-#include <base/logging.h>
-#include <utils/Log.h>
 #include <future>
 
-#include "hci_internals.h"
+#include "os/log.h"
 
 using ::android::bluetooth::root_canal::TestEnvironment;
 
@@ -31,16 +27,16 @@
 constexpr uint16_t kLinkServerPort = 6403;
 
 int main(int argc, char** argv) {
-  ALOGI("main");
+  LOG_INFO("main");
   uint16_t test_port = kTestPort;
   uint16_t hci_server_port = kHciServerPort;
   uint16_t link_server_port = kLinkServerPort;
 
   for (int arg = 0; arg < argc; arg++) {
     int port = atoi(argv[arg]);
-    ALOGI("%d: %s (%d)", arg, argv[arg], port);
+    LOG_INFO("%d: %s (%d)", arg, argv[arg], port);
     if (port < 0 || port > 0xffff) {
-      ALOGW("%s out of range", argv[arg]);
+      LOG_WARN("%s out of range", argv[arg]);
     } else {
       switch (arg) {
         case 0:  // executable name
@@ -55,7 +51,7 @@
           link_server_port = port;
           break;
         default:
-          ALOGW("Ignored option %s", argv[arg]);
+          LOG_WARN("Ignored option %s", argv[arg]);
       }
     }
   }
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
index e5a8d15..f787c51 100644
--- a/vendor_libs/test_vendor_lib/desktop/test_environment.cc
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
@@ -14,17 +14,15 @@
 // limitations under the License.
 //
 
-#define LOG_TAG "root_canal"
-
 #include "test_environment.h"
 
-#include <base/logging.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <string.h>
-#include <utils/Log.h>
+#include <unistd.h>
 
-#include "hci_internals.h"
+#include "os/log.h"
 
 namespace android {
 namespace bluetooth {
@@ -35,7 +33,7 @@
 using test_vendor_lib::TaskCallback;
 
 void TestEnvironment::initialize(std::promise<void> barrier) {
-  ALOGI("%s", __func__);
+  LOG_INFO("%s", __func__);
 
   barrier_ = std::move(barrier);
 
@@ -50,34 +48,34 @@
   SetUpHciServer([this](int fd) { test_model_.IncomingHciConnection(fd); });
   SetUpLinkLayerServer([this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
 
-  ALOGI("%s: Finished", __func__);
+  LOG_INFO("%s: Finished", __func__);
 }
 
 void TestEnvironment::close() {
-  ALOGI("%s", __func__);
+  LOG_INFO("%s", __func__);
 }
 
 void TestEnvironment::SetUpHciServer(const std::function<void(int)>& connection_callback) {
   int socket_fd = remote_hci_transport_.SetUp(hci_server_port_);
 
   test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+      [](const std::string& response) { LOG_INFO("No HCI Response channel: %s", response.c_str()); });
 
   if (socket_fd == -1) {
-    ALOGE("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
+    LOG_ERROR("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
     return;
   }
 
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
     int conn_fd = remote_hci_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching remote HCI channel fd.");
+      LOG_ERROR("Error watching remote HCI channel fd.");
       return;
     }
     int flags = fcntl(conn_fd, F_GETFL, NULL);
     int ret;
     ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
-    CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+    ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
 
     connection_callback(conn_fd);
   });
@@ -87,22 +85,22 @@
   int socket_fd = remote_link_layer_transport_.SetUp(link_server_port_);
 
   test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+      [](const std::string& response) { LOG_INFO("No LinkLayer Response channel: %s", response.c_str()); });
 
   if (socket_fd == -1) {
-    ALOGE("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
+    LOG_ERROR("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
     return;
   }
 
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
     int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching remote LinkLayer channel fd.");
+      LOG_ERROR("Error watching remote LinkLayer channel fd.");
       return;
     }
     int flags = fcntl(conn_fd, F_GETFL, NULL);
     int ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
-    CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+    ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
 
     connection_callback(conn_fd);
   });
@@ -111,14 +109,14 @@
 int TestEnvironment::ConnectToRemoteServer(const std::string& server, int port) {
   int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
   if (socket_fd < 1) {
-    ALOGI("socket() call failed: %s", strerror(errno));
+    LOG_INFO("socket() call failed: %s", strerror(errno));
     return -1;
   }
 
   struct hostent* host;
   host = gethostbyname(server.c_str());
   if (host == NULL) {
-    ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+    LOG_INFO("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
     return -1;
   }
 
@@ -130,13 +128,13 @@
 
   int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
   if (result < 0) {
-    ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+    LOG_INFO("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
     return -1;
   }
 
   int flags = fcntl(socket_fd, F_GETFL, NULL);
   int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
-  CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+  ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
 
   return socket_fd;
 }
@@ -149,22 +147,22 @@
   test_channel_.StartTimer({});
 
   test_channel_.RegisterSendResponse(
-      [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+      [](const std::string& response) { LOG_INFO("No test channel: %s", response.c_str()); });
 
   if (socket_fd == -1) {
-    ALOGE("Test channel SetUp(%d) failed.", test_port_);
+    LOG_ERROR("Test channel SetUp(%d) failed.", test_port_);
     return;
   }
 
-  ALOGI("Test channel SetUp() successful");
+  LOG_INFO("Test channel SetUp() successful");
   async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
     int conn_fd = test_channel_transport_.Accept(socket_fd);
     if (conn_fd < 0) {
-      ALOGE("Error watching test channel fd.");
+      LOG_ERROR("Error watching test channel fd.");
       barrier_.set_value();
       return;
     }
-    ALOGI("Test channel connection accepted.");
+    LOG_INFO("Test channel connection accepted.");
     test_channel_.RegisterSendResponse(
         [this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
 
diff --git a/vendor_libs/test_vendor_lib/include/hci.h b/vendor_libs/test_vendor_lib/include/hci.h
index 11eb029..a2e696b 100644
--- a/vendor_libs/test_vendor_lib/include/hci.h
+++ b/vendor_libs/test_vendor_lib/include/hci.h
@@ -59,5 +59,10 @@
   V5_0 = 9,
 };
 
+enum class Role : uint8_t {
+  MASTER = 0x00,
+  SLAVE = 0x01,
+};
+
 }  // namespace hci
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/event_code.h b/vendor_libs/test_vendor_lib/include/hci/event_code.h
index c0bdcbc..306e522 100644
--- a/vendor_libs/test_vendor_lib/include/hci/event_code.h
+++ b/vendor_libs/test_vendor_lib/include/hci/event_code.h
@@ -49,7 +49,7 @@
   DATA_BUFFER_OVERFLOW = 0x1A,
   MAX_SLOTS_CHANGE = 0x1B,
   READ_CLOCK_OFFSET_COMPLETE = 0x1C,
-  CONNECTION_PACKET_TYPE_CHANGE = 0x1D,
+  CONNECTION_PACKET_TYPE_CHANGED = 0x1D,
   QOS_VIOLATION = 0x1E,
   PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
   FLOW_SPECIFICATION_COMPLETE = 0x21,
diff --git a/vendor_libs/test_vendor_lib/include/hci/op_code.h b/vendor_libs/test_vendor_lib/include/hci/op_code.h
index 931145d..64f9947 100644
--- a/vendor_libs/test_vendor_lib/include/hci/op_code.h
+++ b/vendor_libs/test_vendor_lib/include/hci/op_code.h
@@ -193,7 +193,7 @@
   LE_SET_ADVERTISING_PARAMETERS = LE_CONTROLLER | 0x0006,
   LE_READ_ADVERTISING_CHANNEL_TX_POWER = LE_CONTROLLER | 0x0007,
   LE_SET_ADVERTISING_DATA = LE_CONTROLLER | 0x0008,
-  LE_SET_SCAN_RSPONSE_DATA = LE_CONTROLLER | 0x0009,
+  LE_SET_SCAN_RESPONSE_DATA = LE_CONTROLLER | 0x0009,
   LE_SET_ADVERTISING_ENABLE = LE_CONTROLLER | 0x000A,
   LE_SET_SCAN_PARAMETERS = LE_CONTROLLER | 0x000B,
   LE_SET_SCAN_ENABLE = LE_CONTROLLER | 0x000C,
diff --git a/vendor_libs/test_vendor_lib/include/link.h b/vendor_libs/test_vendor_lib/include/link.h
deleted file mode 100644
index 62c322f..0000000
--- a/vendor_libs/test_vendor_lib/include/link.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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
-
-namespace test_vendor_lib {
-class Link {
- public:
-  static constexpr size_t kSizeBytes = sizeof(uint32_t);
-  static constexpr size_t kTypeBytes = sizeof(uint8_t);
-
-  enum class PacketType : uint8_t {
-    UNKNOWN,
-    ACL,
-    COMMAND,
-    DISCONNECT,
-    ENCRYPT_CONNECTION,
-    ENCRYPT_CONNECTION_RESPONSE,
-    EVENT,
-    INQUIRY,
-    INQUIRY_RESPONSE,
-    IO_CAPABILITY_REQUEST,
-    IO_CAPABILITY_RESPONSE,
-    IO_CAPABILITY_NEGATIVE_RESPONSE,
-    LE_ADVERTISEMENT,
-    LE_SCAN,
-    LE_SCAN_RESPONSE,
-    PAGE,
-    PAGE_RESPONSE,
-    PAGE_REJECT,
-    RESPONSE,
-    SCO,
-  };
-};
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
index 460f550..7e14db6 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
@@ -14,14 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "acl_connection"
-
 #include "acl_connection.h"
 
-#include "base/logging.h"
-
-#include "osi/include/log.h"
-
 using std::shared_ptr;
 
 namespace test_vendor_lib {}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
index 796d04e..cc33c13 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
@@ -18,24 +18,19 @@
 
 #include <cstdint>
 
-#include "types/address.h"
+#include "hci/address.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 // Model the connection of a device to the controller.
 class AclConnection {
  public:
-  AclConnection(const Address& addr) : address_(addr), connected_(false), encrypted_(false) {}
+  AclConnection(Address addr) : address_(addr), address_type_(0), own_address_type_(0) {}
 
   virtual ~AclConnection() = default;
 
-  void SetConnected(bool connected) {
-    connected_ = connected;
-  };
-  bool IsConnected() const {
-    return connected_;
-  };
-
   void Encrypt() {
     encrypted_ = true;
   };
@@ -43,19 +38,33 @@
     return encrypted_;
   };
 
-  const Address& GetAddress() const {
+  Address GetAddress() const {
     return address_;
   }
-  void SetAddress(const Address& address) {
+  void SetAddress(Address address) {
     address_ = address;
   }
 
+  uint8_t GetAddressType() const {
+    return address_type_;
+  }
+  void SetAddressType(uint8_t address_type) {
+    address_type_ = address_type;
+  }
+  uint8_t GetOwnAddressType() const {
+    return own_address_type_;
+  }
+  void SetOwnAddressType(uint8_t address_type) {
+    own_address_type_ = address_type;
+  }
+
  private:
   Address address_;
+  uint8_t address_type_;
+  uint8_t own_address_type_;
 
   // State variables
-  bool connected_;
-  bool encrypted_;
+  bool encrypted_{false};
 };
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
index 2d5ff97..014015a 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "acl_connection_handler"
-
 #include "acl_connection_handler.h"
 
-#include "base/logging.h"
+#include "os/log.h"
 
-#include "osi/include/log.h"
-#include "types/address.h"
+#include "hci/address.h"
 
 using std::shared_ptr;
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 bool AclConnectionHandler::HasHandle(uint16_t handle) const {
   if (acl_connections_.count(handle) == 0) {
     return false;
@@ -35,40 +34,89 @@
 }
 
 uint16_t AclConnectionHandler::GetUnusedHandle() {
-  static uint16_t sNextHandle = acl::kReservedHandle - 2;
-  while (acl_connections_.count(sNextHandle) == 1) {
-    sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+  while (acl_connections_.count(last_handle_) == 1) {
+    last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
   }
-  uint16_t unused_handle = sNextHandle;
-  sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+  uint16_t unused_handle = last_handle_;
+  last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
   return unused_handle;
 }
 
-bool AclConnectionHandler::CreatePendingConnection(const Address& addr) {
-  if ((pending_connections_.size() + 1 > max_pending_connections_) || HasPendingConnection(addr)) {
+bool AclConnectionHandler::CreatePendingConnection(
+    Address addr, bool authenticate_on_connect) {
+  if (classic_connection_pending_) {
     return false;
   }
-  pending_connections_.insert(addr);
+  classic_connection_pending_ = true;
+  pending_connection_address_ = addr;
+  authenticate_pending_classic_connection_ = authenticate_on_connect;
   return true;
 }
 
-bool AclConnectionHandler::HasPendingConnection(const Address& addr) {
-  return pending_connections_.count(addr) == 1;
+bool AclConnectionHandler::HasPendingConnection(Address addr) const {
+  return classic_connection_pending_ && pending_connection_address_ == addr;
 }
 
-bool AclConnectionHandler::CancelPendingConnection(const Address& addr) {
-  if (!HasPendingConnection(addr)) {
+bool AclConnectionHandler::AuthenticatePendingConnection() const {
+  return authenticate_pending_classic_connection_;
+}
+
+bool AclConnectionHandler::CancelPendingConnection(Address addr) {
+  if (!classic_connection_pending_ || pending_connection_address_ != addr) {
     return false;
   }
-  pending_connections_.erase(addr);
+  classic_connection_pending_ = false;
+  pending_connection_address_ = Address::kEmpty;
   return true;
 }
 
-uint16_t AclConnectionHandler::CreateConnection(const Address& addr) {
+bool AclConnectionHandler::CreatePendingLeConnection(Address addr, uint8_t address_type) {
+  if (IsDeviceConnected(addr, address_type)) {
+    LOG_INFO("%s: %s (type %hhx) is already connected", __func__, addr.ToString().c_str(), address_type);
+    return false;
+  }
+  if (le_connection_pending_) {
+    LOG_INFO("%s: connection already pending", __func__);
+    return false;
+  }
+  le_connection_pending_ = true;
+  pending_le_connection_address_ = addr;
+  pending_le_connection_address_type_ = address_type;
+  return true;
+}
+
+bool AclConnectionHandler::HasPendingLeConnection(Address addr,
+                                                  uint8_t address_type) const {
+  return le_connection_pending_ && pending_le_connection_address_ == addr &&
+         pending_le_connection_address_type_ == address_type;
+}
+
+bool AclConnectionHandler::CancelPendingLeConnection(Address addr, uint8_t address_type) {
+  if (!le_connection_pending_ || pending_le_connection_address_ != addr ||
+      pending_le_connection_address_type_ != address_type) {
+    return false;
+  }
+  le_connection_pending_ = false;
+  pending_le_connection_address_ = Address::kEmpty;
+  pending_le_connection_address_type_ = 0xba;
+  return true;
+}
+
+uint16_t AclConnectionHandler::CreateConnection(Address addr) {
   if (CancelPendingConnection(addr)) {
     uint16_t handle = GetUnusedHandle();
     acl_connections_.emplace(handle, addr);
-    SetConnected(handle, true);
+    return handle;
+  }
+  return acl::kReservedHandle;
+}
+
+uint16_t AclConnectionHandler::CreateLeConnection(Address addr, uint8_t address_type, uint8_t own_address_type) {
+  if (CancelPendingLeConnection(addr, address_type)) {
+    uint16_t handle = GetUnusedHandle();
+    acl_connections_.emplace(handle, addr);
+    set_own_address_type(handle, own_address_type);
+    SetAddress(handle, addr, address_type);
     return handle;
   }
   return acl::kReservedHandle;
@@ -78,7 +126,7 @@
   return acl_connections_.erase(handle) > 0;
 }
 
-uint16_t AclConnectionHandler::GetHandle(const Address& addr) const {
+uint16_t AclConnectionHandler::GetHandle(Address addr) const {
   for (auto pair : acl_connections_) {
     if (std::get<AclConnection>(pair).GetAddress() == addr) {
       return std::get<0>(pair);
@@ -87,23 +135,41 @@
   return acl::kReservedHandle;
 }
 
-const Address& AclConnectionHandler::GetAddress(uint16_t handle) const {
-  CHECK(HasHandle(handle)) << "Handle unknown " << handle;
+Address AclConnectionHandler::GetAddress(uint16_t handle) const {
+  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
   return acl_connections_.at(handle).GetAddress();
 }
 
-void AclConnectionHandler::SetConnected(uint16_t handle, bool connected) {
-  if (!HasHandle(handle)) {
-    return;
-  }
-  acl_connections_.at(handle).SetConnected(connected);
+uint8_t AclConnectionHandler::GetAddressType(uint16_t handle) const {
+  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+  return acl_connections_.at(handle).GetAddressType();
+}
+
+void AclConnectionHandler::set_own_address_type(uint16_t handle, uint8_t address_type) {
+  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+  acl_connections_.at(handle).SetOwnAddressType(address_type);
+}
+
+uint8_t AclConnectionHandler::GetOwnAddressType(uint16_t handle) const {
+  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+  return acl_connections_.at(handle).GetOwnAddressType();
 }
 
 bool AclConnectionHandler::IsConnected(uint16_t handle) const {
   if (!HasHandle(handle)) {
     return false;
   }
-  return acl_connections_.at(handle).IsConnected();
+  return true;
+}
+
+bool AclConnectionHandler::IsDeviceConnected(Address addr, uint8_t address_type) const {
+  for (auto pair : acl_connections_) {
+    auto connection = std::get<AclConnection>(pair);
+    if (connection.GetAddress() == addr && connection.GetAddressType() == address_type) {
+      return true;
+    }
+  }
+  return false;
 }
 
 void AclConnectionHandler::Encrypt(uint16_t handle) {
@@ -120,11 +186,13 @@
   return acl_connections_.at(handle).IsEncrypted();
 }
 
-void AclConnectionHandler::SetAddress(uint16_t handle, const Address& address) {
+void AclConnectionHandler::SetAddress(uint16_t handle, Address address, uint8_t address_type) {
   if (!HasHandle(handle)) {
     return;
   }
-  acl_connections_.at(handle).SetAddress(address);
+  auto connection = acl_connections_.at(handle);
+  connection.SetAddress(address);
+  connection.SetAddressType(address_type);
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
index fda1d3d..c08f529 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
@@ -21,41 +21,60 @@
 #include <unordered_map>
 
 #include "acl_connection.h"
+#include "hci/address.h"
 #include "include/acl.h"
-#include "types/address.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 class AclConnectionHandler {
  public:
-  AclConnectionHandler(size_t max_pending_connections = 1) : max_pending_connections_(max_pending_connections) {}
+  AclConnectionHandler() = default;
 
   virtual ~AclConnectionHandler() = default;
 
-  bool CreatePendingConnection(const Address& addr);
-  bool HasPendingConnection(const Address& addr);
-  bool CancelPendingConnection(const Address& addr);
+  bool CreatePendingConnection(Address addr, bool authenticate_on_connect);
+  bool HasPendingConnection(Address addr) const;
+  bool CancelPendingConnection(Address addr);
+  bool AuthenticatePendingConnection() const;
 
-  uint16_t CreateConnection(const Address& addr);
+  bool CreatePendingLeConnection(Address addr, uint8_t addr_type);
+  bool HasPendingLeConnection(Address addr, uint8_t addr_type) const;
+  bool CancelPendingLeConnection(Address addr, uint8_t addr_type);
+
+  uint16_t CreateConnection(Address addr);
+  uint16_t CreateLeConnection(Address addr, uint8_t address_type, uint8_t own_address_type);
   bool Disconnect(uint16_t handle);
   bool HasHandle(uint16_t handle) const;
 
-  uint16_t GetHandle(const Address& addr) const;
-  const Address& GetAddress(uint16_t handle) const;
+  uint16_t GetHandle(Address addr) const;
+  Address GetAddress(uint16_t handle) const;
+  uint8_t GetAddressType(uint16_t handle) const;
+  uint8_t GetOwnAddressType(uint16_t handle) const;
 
   void SetConnected(uint16_t handle, bool connected);
   bool IsConnected(uint16_t handle) const;
 
+  bool IsDeviceConnected(Address addr, uint8_t address_type = 0) const;
+
   void Encrypt(uint16_t handle);
   bool IsEncrypted(uint16_t handle) const;
 
-  void SetAddress(uint16_t handle, const Address& address);
+  void SetAddress(uint16_t handle, Address address, uint8_t address_type = 0);  // default to public
 
  private:
   std::unordered_map<uint16_t, AclConnection> acl_connections_;
-  size_t max_pending_connections_;
-  std::set<Address> pending_connections_;
+  bool classic_connection_pending_{false};
+  Address pending_connection_address_{Address::kEmpty};
+  bool authenticate_pending_classic_connection_{false};
+  bool le_connection_pending_{false};
+  Address pending_le_connection_address_{Address::kEmpty};
+  uint8_t pending_le_connection_address_type_{false};
+
   uint16_t GetUnusedHandle();
+  uint16_t last_handle_{acl::kReservedHandle - 2};
+  void set_own_address_type(uint16_t handle, uint8_t own_address_type);
 };
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
index db6b663..75b87b0 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -14,25 +14,20 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "dual_mode_controller"
-
 #include "dual_mode_controller.h"
 
 #include <memory>
 
 #include <base/files/file_util.h>
 #include <base/json/json_reader.h>
-#include <base/logging.h>
 #include <base/values.h>
 
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
 
 #include "hci.h"
-#include "packets/hci/acl_packet_view.h"
 #include "packets/hci/command_packet_view.h"
-#include "packets/hci/event_packet_builder.h"
-#include "packets/hci/sco_packet_view.h"
+#include "packets/packet_view.h"
 
 using std::vector;
 using test_vendor_lib::hci::EventCode;
@@ -54,6 +49,7 @@
 namespace test_vendor_lib {
 constexpr char DualModeController::kControllerPropertiesFile[];
 constexpr uint16_t DualModeController::kSecurityManagerNumKeys;
+constexpr uint16_t kNumCommandPackets = 0x01;
 
 // Device methods.
 void DualModeController::Initialize(const std::vector<std::string>& args) {
@@ -63,7 +59,7 @@
   if (Address::FromString(args[1], addr)) {
     properties_.SetAddress(addr);
   } else {
-    LOG_FATAL(LOG_TAG, "Invalid address: %s", args[1].c_str());
+    LOG_ALWAYS_FATAL("Invalid address: %s", args[1].c_str());
   }
 };
 
@@ -71,7 +67,8 @@
   return "Simulated Bluetooth Controller";
 }
 
-void DualModeController::IncomingPacket(packets::LinkLayerPacketView incoming) {
+void DualModeController::IncomingPacket(
+    model::packets::LinkLayerPacketView incoming) {
   link_layer_controller_.IncomingPacket(incoming);
 }
 
@@ -79,53 +76,17 @@
   link_layer_controller_.TimerTick();
 }
 
-void DualModeController::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send,
-                                             Phy::Type phy_type) {
-  for (auto phy_pair : phy_layers_) {
-    auto phy_list = std::get<1>(phy_pair);
-    if (phy_type != std::get<0>(phy_pair)) {
-      continue;
-    }
-    for (auto phy : phy_list) {
-      phy->Send(to_send);
-    }
-  }
-}
-
-/*
-void DualModeController::AddConnectionAction(const TaskCallback& task,
-                                             uint16_t handle) {
-  for (size_t i = 0; i < connections_.size(); i++)
-    if (connections_[i]->GetHandle() == handle)
-connections_[i]->AddAction(task);
-}
-*/
-
-void DualModeController::SendCommandCompleteSuccess(OpCode command_opcode) const {
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, hci::Status::SUCCESS)
-                  ->ToVector());
-}
-
 void DualModeController::SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const {
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(command_opcode)->ToVector());
-}
+  std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+      std::make_unique<bluetooth::packet::RawBuilder>();
+  raw_builder_ptr->AddOctets1(kNumCommandPackets);
+  raw_builder_ptr->AddOctets2(command_opcode);
+  raw_builder_ptr->AddOctets1(
+      static_cast<uint8_t>(bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND));
 
-void DualModeController::SendCommandCompleteOnlyStatus(OpCode command_opcode, hci::Status status) const {
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, status)->ToVector());
-}
-
-void DualModeController::SendCommandCompleteStatusAndAddress(OpCode command_opcode, hci::Status status,
-                                                             const Address& address) const {
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(command_opcode, status, address)
-                  ->ToVector());
-}
-
-void DualModeController::SendCommandStatus(hci::Status status, OpCode command_opcode) const {
-  send_event_(packets::EventPacketBuilder::CreateCommandStatusEvent(status, command_opcode)->ToVector());
-}
-
-void DualModeController::SendCommandStatusSuccess(OpCode command_opcode) const {
-  SendCommandStatus(hci::Status::SUCCESS, command_opcode);
+  auto packet = bluetooth::hci::EventPacketBuilder::Create(
+      bluetooth::hci::EventCode::COMMAND_COMPLETE, std::move(raw_builder_ptr));
+  send_event_(std::move(packet));
 }
 
 DualModeController::DualModeController(const std::string& properties_filename, uint16_t num_keys)
@@ -133,11 +94,12 @@
   loopback_mode_ = hci::LoopbackMode::NO;
 
   Address public_address;
-  CHECK(Address::FromString("3C:5A:B4:04:05:06", public_address));
+  ASSERT(Address::FromString("3C:5A:B4:04:05:06", public_address));
   properties_.SetAddress(public_address);
 
   link_layer_controller_.RegisterRemoteChannel(
-      [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+      [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+             Phy::Type phy_type) {
         DualModeController::SendLinkLayerPacket(packet, phy_type);
       });
 
@@ -147,12 +109,15 @@
   SET_HANDLER(OpCode::READ_BUFFER_SIZE, HciReadBufferSize);
   SET_HANDLER(OpCode::HOST_BUFFER_SIZE, HciHostBufferSize);
   SET_HANDLER(OpCode::SNIFF_SUBRATING, HciSniffSubrating);
+  SET_HANDLER(OpCode::READ_ENCRYPTION_KEY_SIZE, HciReadEncryptionKeySize);
   SET_HANDLER(OpCode::READ_LOCAL_VERSION_INFORMATION, HciReadLocalVersionInformation);
   SET_HANDLER(OpCode::READ_BD_ADDR, HciReadBdAddr);
   SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, HciReadLocalSupportedCommands);
+  SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_FEATURES, HciReadLocalSupportedFeatures);
   SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
   SET_HANDLER(OpCode::READ_LOCAL_EXTENDED_FEATURES, HciReadLocalExtendedFeatures);
   SET_HANDLER(OpCode::READ_REMOTE_EXTENDED_FEATURES, HciReadRemoteExtendedFeatures);
+  SET_HANDLER(OpCode::SWITCH_ROLE, HciSwitchRole);
   SET_HANDLER(OpCode::READ_REMOTE_SUPPORTED_FEATURES, HciReadRemoteSupportedFeatures);
   SET_HANDLER(OpCode::READ_CLOCK_OFFSET, HciReadClockOffset);
   SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_REPLY, HciIoCapabilityRequestReply);
@@ -161,23 +126,33 @@
   SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, HciIoCapabilityRequestNegativeReply);
   SET_HANDLER(OpCode::WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
   SET_HANDLER(OpCode::WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+  SET_HANDLER(OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT,
+              HciWriteSecureConnectionsHostSupport);
   SET_HANDLER(OpCode::SET_EVENT_MASK, HciSetEventMask);
   SET_HANDLER(OpCode::WRITE_INQUIRY_MODE, HciWriteInquiryMode);
   SET_HANDLER(OpCode::WRITE_PAGE_SCAN_TYPE, HciWritePageScanType);
   SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_TYPE, HciWriteInquiryScanType);
   SET_HANDLER(OpCode::AUTHENTICATION_REQUESTED, HciAuthenticationRequested);
   SET_HANDLER(OpCode::SET_CONNECTION_ENCRYPTION, HciSetConnectionEncryption);
+  SET_HANDLER(OpCode::CHANGE_CONNECTION_LINK_KEY, HciChangeConnectionLinkKey);
+  SET_HANDLER(OpCode::MASTER_LINK_KEY, HciMasterLinkKey);
   SET_HANDLER(OpCode::WRITE_AUTHENTICATION_ENABLE, HciWriteAuthenticationEnable);
   SET_HANDLER(OpCode::READ_AUTHENTICATION_ENABLE, HciReadAuthenticationEnable);
   SET_HANDLER(OpCode::WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
   SET_HANDLER(OpCode::WRITE_PAGE_TIMEOUT, HciWritePageTimeout);
   SET_HANDLER(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, HciWriteLinkSupervisionTimeout);
+  SET_HANDLER(OpCode::HOLD_MODE, HciHoldMode);
+  SET_HANDLER(OpCode::SNIFF_MODE, HciSniffMode);
+  SET_HANDLER(OpCode::EXIT_SNIFF_MODE, HciExitSniffMode);
+  SET_HANDLER(OpCode::QOS_SETUP, HciQosSetup);
   SET_HANDLER(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+  SET_HANDLER(OpCode::FLOW_SPECIFICATION, HciFlowSpecification);
   SET_HANDLER(OpCode::WRITE_LINK_POLICY_SETTINGS, HciWriteLinkPolicySettings);
   SET_HANDLER(OpCode::CHANGE_CONNECTION_PACKET_TYPE, HciChangeConnectionPacketType);
   SET_HANDLER(OpCode::WRITE_LOCAL_NAME, HciWriteLocalName);
   SET_HANDLER(OpCode::READ_LOCAL_NAME, HciReadLocalName);
   SET_HANDLER(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE, HciWriteExtendedInquiryResponse);
+  SET_HANDLER(OpCode::REFRESH_ENCRYPTION_KEY, HciRefreshEncryptionKey);
   SET_HANDLER(OpCode::WRITE_VOICE_SETTING, HciWriteVoiceSetting);
   SET_HANDLER(OpCode::WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
   SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY, HciWriteInquiryScanActivity);
@@ -195,8 +170,10 @@
   SET_HANDLER(OpCode::LE_READ_BUFFER_SIZE, HciLeReadBufferSize);
   SET_HANDLER(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, HciLeReadLocalSupportedFeatures);
   SET_HANDLER(OpCode::LE_SET_RANDOM_ADDRESS, HciLeSetRandomAddress);
-  SET_HANDLER(OpCode::LE_SET_ADVERTISING_DATA, HciLeSetAdvertisingData);
   SET_HANDLER(OpCode::LE_SET_ADVERTISING_PARAMETERS, HciLeSetAdvertisingParameters);
+  SET_HANDLER(OpCode::LE_SET_ADVERTISING_DATA, HciLeSetAdvertisingData);
+  SET_HANDLER(OpCode::LE_SET_SCAN_RESPONSE_DATA, HciLeSetScanResponseData);
+  SET_HANDLER(OpCode::LE_SET_ADVERTISING_ENABLE, HciLeSetAdvertisingEnable);
   SET_HANDLER(OpCode::LE_SET_SCAN_PARAMETERS, HciLeSetScanParameters);
   SET_HANDLER(OpCode::LE_SET_SCAN_ENABLE, HciLeSetScanEnable);
   SET_HANDLER(OpCode::LE_CREATE_CONNECTION, HciLeCreateConnection);
@@ -218,6 +195,12 @@
   SET_HANDLER(OpCode::READ_REMOTE_VERSION_INFORMATION, HciReadRemoteVersionInformation);
   SET_HANDLER(OpCode::LE_CONNECTION_UPDATE, HciLeConnectionUpdate);
   SET_HANDLER(OpCode::LE_START_ENCRYPTION, HciLeStartEncryption);
+  SET_HANDLER(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST,
+              HciLeAddDeviceToResolvingList);
+  SET_HANDLER(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST,
+              HciLeRemoveDeviceFromResolvingList);
+  SET_HANDLER(OpCode::LE_CLEAR_RESOLVING_LIST, HciLeClearResolvingList);
+  SET_HANDLER(OpCode::LE_SET_PRIVACY_MODE, HciLeSetPrivacyMode);
   // Testing Commands
   SET_HANDLER(OpCode::READ_LOOPBACK_MODE, HciReadLoopbackMode);
   SET_HANDLER(OpCode::WRITE_LOOPBACK_MODE, HciWriteLoopbackMode);
@@ -225,11 +208,13 @@
 }
 
 void DualModeController::HciSniffSubrating(packets::PacketView<true> args) {
-  CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  send_event_(packets::EventPacketBuilder::CreateSniffSubratingEvent(hci::Status::SUCCESS, handle)->ToVector());
+  auto packet = bluetooth::hci::SniffSubratingCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, handle);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::RegisterTaskScheduler(
@@ -248,11 +233,20 @@
 }
 
 void DualModeController::HandleAcl(std::shared_ptr<std::vector<uint8_t>> packet) {
-  auto acl_packet = packets::AclPacketView::Create(packet);
+  bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet);
+  auto acl_packet = bluetooth::hci::AclPacketView::Create(raw_packet);
+  ASSERT(acl_packet.IsValid());
   if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
     uint16_t handle = acl_packet.GetHandle();
-    send_acl_(packet);
-    send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+
+    std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+    bluetooth::hci::CompletedPackets cp;
+    cp.connection_handle_ = handle;
+    cp.host_num_of_completed_packets_ = kNumCommandPackets;
+    completed_packets.push_back(cp);
+    auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+        completed_packets);
+    send_event_(std::move(packet));
     return;
   }
 
@@ -260,15 +254,28 @@
 }
 
 void DualModeController::HandleSco(std::shared_ptr<std::vector<uint8_t>> packet) {
-  auto sco_packet = packets::ScoPacketView::Create(packet);
+  bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet);
+  auto sco_packet = bluetooth::hci::ScoPacketView::Create(raw_packet);
   if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
     uint16_t handle = sco_packet.GetHandle();
     send_sco_(packet);
-    send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+    std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+    bluetooth::hci::CompletedPackets cp;
+    cp.connection_handle_ = handle;
+    cp.host_num_of_completed_packets_ = kNumCommandPackets;
+    completed_packets.push_back(cp);
+    auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+        completed_packets);
+    send_event_(std::move(packet));
     return;
   }
 }
 
+void DualModeController::HandleIso(
+    std::shared_ptr<std::vector<uint8_t>> /* packet */) {
+  // TODO: implement handling similar to HandleSco
+}
+
 void DualModeController::HandleCommand(std::shared_ptr<std::vector<uint8_t>> packet) {
   auto command_packet = packets::CommandPacketView::Create(packet);
   uint16_t opcode = command_packet.GetOpcode();
@@ -279,25 +286,45 @@
       op != OpCode::RESET && op != OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL && op != OpCode::HOST_BUFFER_SIZE &&
       op != OpCode::HOST_NUM_COMPLETED_PACKETS && op != OpCode::READ_BUFFER_SIZE && op != OpCode::READ_LOOPBACK_MODE &&
       op != OpCode::WRITE_LOOPBACK_MODE) {
-    send_event_(packets::EventPacketBuilder::CreateLoopbackCommandEvent(op, command_packet.GetPayload())->ToVector());
+    std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+        std::make_unique<bluetooth::packet::RawBuilder>();
+    raw_builder_ptr->AddOctets(*packet);
+    auto packet = bluetooth::hci::LoopbackCommandBuilder::Create(
+        std::move(raw_builder_ptr));
+    send_event_(std::move(packet));
   } else if (active_hci_commands_.count(opcode) > 0) {
     active_hci_commands_[opcode](command_packet.GetPayload());
   } else {
     SendCommandCompleteUnknownOpCodeEvent(opcode);
-    LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode, opcode & 0xFC00, opcode & 0x03FF);
+    LOG_INFO("Unknown command, opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X",
+             opcode, (opcode & 0xFC00) >> 10, opcode & 0x03FF);
   }
 }
 
 void DualModeController::RegisterEventChannel(
     const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
-  link_layer_controller_.RegisterEventChannel(callback);
-  send_event_ = callback;
+  send_event_ =
+      [callback](std::shared_ptr<bluetooth::hci::EventPacketBuilder> event) {
+        auto bytes = std::make_shared<std::vector<uint8_t>>();
+        bluetooth::packet::BitInserter bit_inserter(*bytes);
+        bytes->reserve(event->size());
+        event->Serialize(bit_inserter);
+        callback(std::move(bytes));
+      };
+  link_layer_controller_.RegisterEventChannel(send_event_);
 }
 
 void DualModeController::RegisterAclChannel(
     const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
-  link_layer_controller_.RegisterAclChannel(callback);
-  send_acl_ = callback;
+  send_acl_ =
+      [callback](std::shared_ptr<bluetooth::hci::AclPacketBuilder> acl_data) {
+        auto bytes = std::make_shared<std::vector<uint8_t>>();
+        bluetooth::packet::BitInserter bit_inserter(*bytes);
+        bytes->reserve(acl_data->size());
+        acl_data->Serialize(bit_inserter);
+        callback(std::move(bytes));
+      };
+  link_layer_controller_.RegisterAclChannel(send_acl_);
 }
 
 void DualModeController::RegisterScoChannel(
@@ -306,117 +333,199 @@
   send_sco_ = callback;
 }
 
+void DualModeController::RegisterIsoChannel(
+    const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+        callback) {
+  link_layer_controller_.RegisterIsoChannel(callback);
+  send_iso_ = callback;
+}
+
 void DualModeController::HciReset(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.Reset();
   if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
     loopback_mode_ = hci::LoopbackMode::NO;
   }
 
-  SendCommandCompleteSuccess(OpCode::RESET);
+  send_event_(bluetooth::hci::ResetCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS));
 }
 
 void DualModeController::HciReadBufferSize(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadBufferSize(
-          hci::Status::SUCCESS, properties_.GetAclDataPacketSize(), properties_.GetSynchronousDataPacketSize(),
-          properties_.GetTotalNumAclDataPackets(), properties_.GetTotalNumSynchronousDataPackets());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
 
-  send_event_(command_complete->ToVector());
+  auto packet = bluetooth::hci::ReadBufferSizeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      properties_.GetAclDataPacketSize(),
+      properties_.GetSynchronousDataPacketSize(),
+      properties_.GetTotalNumAclDataPackets(),
+      properties_.GetTotalNumSynchronousDataPackets());
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadEncryptionKeySize(
+    packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+
+  uint16_t handle = args.begin().extract<uint16_t>();
+
+  auto packet = bluetooth::hci::ReadEncryptionKeySizeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, handle,
+      properties_.GetEncryptionKeySize());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciHostBufferSize(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::HOST_BUFFER_SIZE);
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::HostBufferSizeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadLocalVersionInformation(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
-          hci::Status::SUCCESS, properties_.GetVersion(), properties_.GetRevision(), properties_.GetLmpPalVersion(),
-          properties_.GetManufacturerName(), properties_.GetLmpPalSubversion());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+
+  bluetooth::hci::LocalVersionInformation local_version_information;
+  local_version_information.hci_version_ =
+      static_cast<bluetooth::hci::HciVersion>(properties_.GetVersion());
+  local_version_information.hci_revision_ = properties_.GetRevision();
+  local_version_information.lmp_version_ =
+      static_cast<bluetooth::hci::LmpVersion>(properties_.GetLmpPalVersion());
+  local_version_information.manufacturer_name_ =
+      properties_.GetManufacturerName();
+  local_version_information.lmp_subversion_ = properties_.GetLmpPalSubversion();
+  auto packet =
+      bluetooth::hci::ReadLocalVersionInformationCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+          local_version_information);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadRemoteVersionInformation(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  hci::Status status =
-      link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_VERSION_INFORMATION, args, handle);
+  auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode::READ_REMOTE_VERSION_INFORMATION, args, handle);
 
-  SendCommandStatus(status, OpCode::READ_REMOTE_VERSION_INFORMATION);
+  auto packet =
+      bluetooth::hci::ReadRemoteVersionInformationStatusBuilder::Create(
+          status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadBdAddr(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status::SUCCESS, properties_.GetAddress());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::ReadBdAddrCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      properties_.GetAddress());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadLocalSupportedCommands(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(hci::Status::SUCCESS,
-                                                                                   properties_.GetSupportedCommands());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+
+  std::array<uint8_t, 64> supported_commands;
+  supported_commands.fill(0x00);
+  size_t len = properties_.GetSupportedCommands().size();
+  if (len > 64) {
+    len = 64;
+  }
+  std::copy_n(properties_.GetSupportedCommands().begin(), len,
+              supported_commands.begin());
+
+  auto packet =
+      bluetooth::hci::ReadLocalSupportedCommandsCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+          supported_commands);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadLocalSupportedFeatures(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet =
+      bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+          properties_.GetSupportedFeatures());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadLocalSupportedCodecs(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
-          hci::Status::SUCCESS, properties_.GetSupportedCodecs(), properties_.GetVendorSpecificCodecs());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::ReadLocalSupportedCodecsCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      properties_.GetSupportedCodecs(), properties_.GetVendorSpecificCodecs());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadLocalExtendedFeatures(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
   uint8_t page_number = args.begin().extract<uint8_t>();
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
-                  hci::Status::SUCCESS, page_number, properties_.GetExtendedFeaturesMaximumPageNumber(),
-                  properties_.GetExtendedFeatures(page_number))
-                  ->ToVector());
+
+  auto pakcet =
+      bluetooth::hci::ReadLocalExtendedFeaturesCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, page_number,
+          properties_.GetExtendedFeaturesMaximumPageNumber(),
+          properties_.GetExtendedFeatures(page_number));
+  send_event_(std::move(pakcet));
 }
 
 void DualModeController::HciReadRemoteExtendedFeatures(packets::PacketView<true> args) {
-  CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 3, "%s  size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  hci::Status status =
-      link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_EXTENDED_FEATURES, args, handle);
+  auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode::READ_REMOTE_EXTENDED_FEATURES, args, handle);
 
-  SendCommandStatus(status, OpCode::READ_REMOTE_EXTENDED_FEATURES);
+  auto packet = bluetooth::hci::ReadRemoteExtendedFeaturesStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciSwitchRole(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
+
+  Address address = args.begin().extract<Address>();
+  uint8_t role = args.begin().extract<uint8_t>();
+
+  auto status = link_layer_controller_.SwitchRole(address, role);
+
+  auto packet = bluetooth::hci::SwitchRoleStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadRemoteSupportedFeatures(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  hci::Status status =
-      link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_SUPPORTED_FEATURES, args, handle);
+  auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES, args, handle);
 
-  SendCommandStatus(status, OpCode::READ_REMOTE_SUPPORTED_FEATURES);
+  auto packet =
+      bluetooth::hci::ReadRemoteSupportedFeaturesStatusBuilder::Create(
+          status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadClockOffset(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  hci::Status status = link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_CLOCK_OFFSET, args, handle);
+  auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode::READ_CLOCK_OFFSET, args, handle);
 
-  SendCommandStatus(status, OpCode::READ_CLOCK_OFFSET);
+  auto packet = bluetooth::hci::ReadClockOffsetStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciIoCapabilityRequestReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 9) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 9, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   Address peer = args_itr.extract<Address>();
@@ -424,56 +533,71 @@
   uint8_t oob_data_present_flag = args_itr.extract<uint8_t>();
   uint8_t authentication_requirements = args_itr.extract<uint8_t>();
 
-  hci::Status status = link_layer_controller_.IoCapabilityRequestReply(peer, io_capability, oob_data_present_flag,
-                                                                       authentication_requirements);
+  auto status = link_layer_controller_.IoCapabilityRequestReply(
+      peer, io_capability, oob_data_present_flag, authentication_requirements);
+  auto packet = bluetooth::hci::IoCapabilityRequestReplyCompleteBuilder::Create(
+      kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciUserConfirmationRequestReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
 
   Address peer = args.begin().extract<Address>();
 
-  hci::Status status = link_layer_controller_.UserConfirmationRequestReply(peer);
+  auto status = link_layer_controller_.UserConfirmationRequestReply(peer);
+  auto packet =
+      bluetooth::hci::UserConfirmationRequestReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciUserConfirmationRequestNegativeReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
 
   Address peer = args.begin().extract<Address>();
 
-  hci::Status status = link_layer_controller_.UserConfirmationRequestNegativeReply(peer);
+  auto status =
+      link_layer_controller_.UserConfirmationRequestNegativeReply(peer);
+  auto packet =
+      bluetooth::hci::UserConfirmationRequestNegativeReplyCompleteBuilder::
+          Create(kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciUserPasskeyRequestReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 10, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   Address peer = args_itr.extract<Address>();
   uint32_t numeric_value = args_itr.extract<uint32_t>();
 
-  hci::Status status = link_layer_controller_.UserPasskeyRequestReply(peer, numeric_value);
+  auto status =
+      link_layer_controller_.UserPasskeyRequestReply(peer, numeric_value);
+  auto packet = bluetooth::hci::UserPasskeyRequestReplyCompleteBuilder::Create(
+      kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciUserPasskeyRequestNegativeReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
 
   Address peer = args.begin().extract<Address>();
 
-  hci::Status status = link_layer_controller_.UserPasskeyRequestNegativeReply(peer);
+  auto status = link_layer_controller_.UserPasskeyRequestNegativeReply(peer);
+  auto packet =
+      bluetooth::hci::UserPasskeyRequestNegativeReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciRemoteOobDataRequestReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 38) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 38, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   Address peer = args_itr.extract<Address>();
@@ -485,252 +609,469 @@
   for (size_t i = 0; i < 16; i++) {
     r.push_back(args_itr.extract<uint8_t>());
   }
-  hci::Status status = link_layer_controller_.RemoteOobDataRequestReply(peer, c, r);
+  auto status = link_layer_controller_.RemoteOobDataRequestReply(peer, c, r);
+  auto packet =
+      bluetooth::hci::RemoteOobDataRequestReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciRemoteOobDataRequestNegativeReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
 
   Address peer = args.begin().extract<Address>();
 
-  hci::Status status = link_layer_controller_.RemoteOobDataRequestNegativeReply(peer);
+  auto status = link_layer_controller_.RemoteOobDataRequestNegativeReply(peer);
+  auto packet =
+      bluetooth::hci::RemoteOobDataRequestNegativeReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciIoCapabilityRequestNegativeReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   Address peer = args_itr.extract<Address>();
   hci::Status reason = args_itr.extract<hci::Status>();
 
-  hci::Status status = link_layer_controller_.IoCapabilityRequestNegativeReply(peer, reason);
+  auto status =
+      link_layer_controller_.IoCapabilityRequestNegativeReply(peer, reason);
+  auto packet =
+      bluetooth::hci::IoCapabilityRequestNegativeReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, peer);
 
-  SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, status, peer);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteSimplePairingMode(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
-  CHECK(args[0] == 1 || args[0] == 0);
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  ASSERT(args[0] == 1 || args[0] == 0);
   link_layer_controller_.WriteSimplePairingMode(args[0] == 1);
-  SendCommandCompleteSuccess(OpCode::WRITE_SIMPLE_PAIRING_MODE);
+  auto packet = bluetooth::hci::WriteSimplePairingModeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciChangeConnectionPacketType(packets::PacketView<true> args) {
-  CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 4, "%s  size=%zu", __func__, args.size());
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
   uint16_t packet_type = args_itr.extract<uint16_t>();
 
-  hci::Status status = link_layer_controller_.ChangeConnectionPacketType(handle, packet_type);
+  auto status =
+      link_layer_controller_.ChangeConnectionPacketType(handle, packet_type);
 
-  SendCommandStatus(status, OpCode::CHANGE_CONNECTION_PACKET_TYPE);
+  auto packet = bluetooth::hci::ChangeConnectionPacketTypeStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteLeHostSupport(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_LE_HOST_SUPPORT);
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WriteLeHostSupportCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteSecureConnectionsHostSupport(
+    packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  properties_.SetExtendedFeatures(properties_.GetExtendedFeatures(1) | 0x8, 1);
+  auto packet =
+      bluetooth::hci::WriteSecureConnectionsHostSupportCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciSetEventMask(packets::PacketView<true> args) {
-  CHECK(args.size() == 8) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::SET_EVENT_MASK);
+  ASSERT_LOG(args.size() == 8, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::SetEventMaskCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteInquiryMode(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.SetInquiryMode(args[0]);
-  SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_MODE);
+  auto packet = bluetooth::hci::WriteInquiryModeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWritePageScanType(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_PAGE_SCAN_TYPE);
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WritePageScanTypeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteInquiryScanType(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_TYPE);
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WriteInquiryScanTypeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciAuthenticationRequested(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
   uint16_t handle = args.begin().extract<uint16_t>();
-  hci::Status status = link_layer_controller_.AuthenticationRequested(handle);
+  auto status = link_layer_controller_.AuthenticationRequested(handle);
 
-  SendCommandStatus(status, OpCode::AUTHENTICATION_REQUESTED);
+  auto packet = bluetooth::hci::AuthenticationRequestedStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciSetConnectionEncryption(packets::PacketView<true> args) {
-  CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 3, "%s  size=%zu", __func__, args.size());
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
   uint8_t encryption_enable = args_itr.extract<uint8_t>();
-  hci::Status status = link_layer_controller_.SetConnectionEncryption(handle, encryption_enable);
+  auto status =
+      link_layer_controller_.SetConnectionEncryption(handle, encryption_enable);
 
-  SendCommandStatus(status, OpCode::SET_CONNECTION_ENCRYPTION);
+  auto packet = bluetooth::hci::SetConnectionEncryptionStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciChangeConnectionLinkKey(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+
+  auto status = link_layer_controller_.ChangeConnectionLinkKey(handle);
+
+  auto packet = bluetooth::hci::ChangeConnectionLinkKeyStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciMasterLinkKey(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint8_t key_flag = args_itr.extract<uint8_t>();
+
+  auto status = link_layer_controller_.MasterLinkKey(key_flag);
+
+  auto packet = bluetooth::hci::MasterLinkKeyStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteAuthenticationEnable(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
   properties_.SetAuthenticationEnable(args[0]);
-  SendCommandCompleteSuccess(OpCode::WRITE_AUTHENTICATION_ENABLE);
+  auto packet =
+      bluetooth::hci::WriteAuthenticationEnableCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadAuthenticationEnable(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(hci::Status::SUCCESS,
-                                                                                 properties_.GetAuthenticationEnable());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::ReadAuthenticationEnableCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      static_cast<bluetooth::hci::AuthenticationEnable>(
+          properties_.GetAuthenticationEnable()));
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteClassOfDevice(packets::PacketView<true> args) {
-  CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 3, "%s  size=%zu", __func__, args.size());
   properties_.SetClassOfDevice(args[0], args[1], args[2]);
-  SendCommandCompleteSuccess(OpCode::WRITE_CLASS_OF_DEVICE);
+  auto packet = bluetooth::hci::WriteClassOfDeviceCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWritePageTimeout(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_PAGE_TIMEOUT);
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WritePageTimeoutCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciHoldMode(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+  uint16_t hold_mode_max_interval = args_itr.extract<uint16_t>();
+  uint16_t hold_mode_min_interval = args_itr.extract<uint16_t>();
+
+  auto status = link_layer_controller_.HoldMode(handle, hold_mode_max_interval,
+                                                hold_mode_min_interval);
+
+  auto packet =
+      bluetooth::hci::HoldModeStatusBuilder::Create(status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciSniffMode(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 10, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+  uint16_t sniff_max_interval = args_itr.extract<uint16_t>();
+  uint16_t sniff_min_interval = args_itr.extract<uint16_t>();
+  uint16_t sniff_attempt = args_itr.extract<uint16_t>();
+  uint16_t sniff_timeout = args_itr.extract<uint16_t>();
+
+  auto status = link_layer_controller_.SniffMode(handle, sniff_max_interval,
+                                                 sniff_min_interval,
+                                                 sniff_attempt, sniff_timeout);
+
+  auto packet = bluetooth::hci::SniffModeStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciExitSniffMode(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+
+  auto status = link_layer_controller_.ExitSniffMode(handle);
+
+  auto packet = bluetooth::hci::ExitSniffModeStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciQosSetup(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 20, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+  args_itr.extract<uint8_t>();  // unused
+  uint8_t service_type = args_itr.extract<uint8_t>();
+  uint32_t token_rate = args_itr.extract<uint32_t>();
+  uint32_t peak_bandwidth = args_itr.extract<uint32_t>();
+  uint32_t latency = args_itr.extract<uint32_t>();
+  uint32_t delay_variation = args_itr.extract<uint32_t>();
+
+  auto status =
+      link_layer_controller_.QosSetup(handle, service_type, token_rate,
+                                      peak_bandwidth, latency, delay_variation);
+
+  auto packet =
+      bluetooth::hci::QosSetupStatusBuilder::Create(status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto packet =
+      bluetooth::hci::WriteDefaultLinkPolicySettingsCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciFlowSpecification(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 21, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+  args_itr.extract<uint8_t>();  // unused
+  uint8_t flow_direction = args_itr.extract<uint8_t>();
+  uint8_t service_type = args_itr.extract<uint8_t>();
+  uint32_t token_rate = args_itr.extract<uint32_t>();
+  uint32_t token_bucket_size = args_itr.extract<uint32_t>();
+  uint32_t peak_bandwidth = args_itr.extract<uint32_t>();
+  uint32_t access_latency = args_itr.extract<uint32_t>();
+
+  auto status = link_layer_controller_.FlowSpecification(
+      handle, flow_direction, service_type, token_rate, token_bucket_size,
+      peak_bandwidth, access_latency);
+
+  auto packet = bluetooth::hci::FlowSpecificationStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteLinkPolicySettings(packets::PacketView<true> args) {
-  CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 4, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
   uint16_t settings = args_itr.extract<uint16_t>();
 
-  hci::Status status = link_layer_controller_.WriteLinkPolicySettings(handle, settings);
+  auto status =
+      link_layer_controller_.WriteLinkPolicySettings(handle, settings);
 
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(status, handle)->ToVector());
+  auto packet = bluetooth::hci::WriteLinkPolicySettingsCompleteBuilder::Create(
+      kNumCommandPackets, status, handle);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteLinkSupervisionTimeout(packets::PacketView<true> args) {
-  CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 4, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
   uint16_t timeout = args_itr.extract<uint16_t>();
 
-  hci::Status status = link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout);
-
-  send_event_(
-      packets::EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(status, handle)->ToVector());
+  auto status =
+      link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout);
+  auto packet =
+      bluetooth::hci::WriteLinkSupervisionTimeoutCompleteBuilder::Create(
+          kNumCommandPackets, status, handle);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciReadLocalName(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteReadLocalName(hci::Status::SUCCESS, properties_.GetName());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+
+  std::array<uint8_t, 248> local_name;
+  local_name.fill(0x00);
+  size_t len = properties_.GetName().size();
+  if (len > 247) {
+    len = 247;  // one byte for NULL octet (0x00)
+  }
+  std::copy_n(properties_.GetName().begin(), len, local_name.begin());
+
+  auto packet = bluetooth::hci::ReadLocalNameCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, local_name);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteLocalName(packets::PacketView<true> args) {
-  CHECK(args.size() == 248) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 248, "%s  size=%zu", __func__, args.size());
   std::vector<uint8_t> clipped(args.begin(), args.begin() + LastNonZero(args) + 1);
   properties_.SetName(clipped);
-  SendCommandCompleteSuccess(OpCode::WRITE_LOCAL_NAME);
+  auto packet = bluetooth::hci::WriteLocalNameCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteExtendedInquiryResponse(packets::PacketView<true> args) {
-  CHECK(args.size() == 241) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 241, "%s  size=%zu", __func__, args.size());
   // Strip FEC byte and trailing zeros
   std::vector<uint8_t> clipped(args.begin() + 1, args.begin() + LastNonZero(args) + 1);
   properties_.SetExtendedInquiryData(clipped);
-  LOG_WARN(LOG_TAG, "Write EIR Inquiry - Size = %d (%d)", static_cast<int>(properties_.GetExtendedInquiryData().size()),
-           static_cast<int>(clipped.size()));
-  SendCommandCompleteSuccess(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE);
+  auto packet =
+      bluetooth::hci::WriteExtendedInquiryResponseCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciRefreshEncryptionKey(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  uint16_t handle = args_itr.extract<uint16_t>();
+  auto status_packet =
+      bluetooth::hci::RefreshEncryptionKeyStatusBuilder::Create(
+          bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+  send_event_(std::move(status_packet));
+  // TODO: Support this in the link layer
+  auto complete_packet =
+      bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create(
+          bluetooth::hci::ErrorCode::SUCCESS, handle);
+  send_event_(std::move(complete_packet));
 }
 
 void DualModeController::HciWriteVoiceSetting(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_VOICE_SETTING);
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WriteVoiceSettingCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteCurrentIacLap(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  CHECK(args.size() == 1 + (3 * args[0]));  // count + 3-byte IACs
-
-  SendCommandCompleteSuccess(OpCode::WRITE_CURRENT_IAC_LAP);
+  ASSERT(args.size() > 0);
+  ASSERT(args.size() == 1 + (3 * args[0]));  // count + 3-byte IACs
+  auto packet = bluetooth::hci::WriteCurrentIacLapCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteInquiryScanActivity(packets::PacketView<true> args) {
-  CHECK(args.size() == 4) << __func__ << " size=" << args.size();
-  SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY);
+  ASSERT_LOG(args.size() == 4, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::WriteInquiryScanActivityCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteScanEnable(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.SetInquiryScanEnable(args[0] & 0x1);
   link_layer_controller_.SetPageScanEnable(args[0] & 0x2);
-  SendCommandCompleteSuccess(OpCode::WRITE_SCAN_ENABLE);
+  auto packet = bluetooth::hci::WriteScanEnableCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciSetEventFilter(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteSuccess(OpCode::SET_EVENT_FILTER);
+  ASSERT(args.size() > 0);
+  auto packet = bluetooth::hci::SetEventFilterCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciInquiry(packets::PacketView<true> args) {
-  CHECK(args.size() == 5) << __func__ << " size=" << args.size();
-  link_layer_controller_.SetInquiryLAP(args[0] | (args[1] << 8) | (args[2] << 16));
+  ASSERT_LOG(args.size() == 5, "%s  size=%zu", __func__, args.size());
+  link_layer_controller_.SetInquiryLAP(args[0] | (args[1], 8) | (args[2], 16));
   link_layer_controller_.SetInquiryMaxResponses(args[4]);
   link_layer_controller_.StartInquiry(std::chrono::milliseconds(args[3] * 1280));
 
-  SendCommandStatusSuccess(OpCode::INQUIRY);
+  auto packet = bluetooth::hci::InquiryStatusBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciInquiryCancel(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.InquiryCancel();
-  SendCommandCompleteSuccess(OpCode::INQUIRY_CANCEL);
+  auto packet = bluetooth::hci::InquiryCancelCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciAcceptConnectionRequest(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
   Address addr = args.begin().extract<Address>();
   bool try_role_switch = args[6] == 0;
-  hci::Status status = link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch);
-  SendCommandStatus(status, OpCode::ACCEPT_CONNECTION_REQUEST);
+  auto status =
+      link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch);
+  auto packet = bluetooth::hci::AcceptConnectionRequestStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciRejectConnectionRequest(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
   auto args_itr = args.begin();
   Address addr = args_itr.extract<Address>();
   uint8_t reason = args_itr.extract<uint8_t>();
-  hci::Status status = link_layer_controller_.RejectConnectionRequest(addr, reason);
-  SendCommandStatus(status, OpCode::REJECT_CONNECTION_REQUEST);
+  auto status = link_layer_controller_.RejectConnectionRequest(addr, reason);
+  auto packet = bluetooth::hci::RejectConnectionRequestStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLinkKeyRequestReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 22) << __func__ << " size=" << args.size();
-  Address addr = args.begin().extract<Address>();
-  packets::PacketView<true> key = args.SubViewLittleEndian(6, 22);
-  hci::Status status = link_layer_controller_.LinkKeyRequestReply(addr, key);
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(status, addr)->ToVector());
+  ASSERT_LOG(args.size() == 22, "%s  size=%zu", __func__, args.size());
+  auto args_it = args.begin();
+  Address addr = args_it.extract<Address>();
+  auto key = args.begin().extract<std::array<uint8_t, 16>>();
+  auto status = link_layer_controller_.LinkKeyRequestReply(addr, key);
+  auto packet = bluetooth::hci::LinkKeyRequestReplyCompleteBuilder::Create(
+      kNumCommandPackets, status);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLinkKeyRequestNegativeReply(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
   Address addr = args.begin().extract<Address>();
-  hci::Status status = link_layer_controller_.LinkKeyRequestNegativeReply(addr);
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(status, addr)->ToVector());
+  auto status = link_layer_controller_.LinkKeyRequestNegativeReply(addr);
+  auto packet =
+      bluetooth::hci::LinkKeyRequestNegativeReplyCompleteBuilder::Create(
+          kNumCommandPackets, status, addr);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciDeleteStoredLinkKey(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
 
   uint16_t deleted_keys = 0;
 
@@ -743,83 +1084,130 @@
     security_manager_.DeleteAllKeys();
   }
 
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(hci::Status::SUCCESS, deleted_keys)
-                  ->ToVector());
+  auto packet = bluetooth::hci::DeleteStoredLinkKeyCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, deleted_keys);
+
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciRemoteNameRequest(packets::PacketView<true> args) {
-  CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 10, "%s  size=%zu", __func__, args.size());
 
   Address remote_addr = args.begin().extract<Address>();
 
-  hci::Status status =
-      link_layer_controller_.SendCommandToRemoteByAddress(OpCode::REMOTE_NAME_REQUEST, args, remote_addr, false);
+  auto status = link_layer_controller_.SendCommandToRemoteByAddress(
+      bluetooth::hci::OpCode::REMOTE_NAME_REQUEST, args, remote_addr);
 
-  SendCommandStatus(status, OpCode::REMOTE_NAME_REQUEST);
+  auto packet = bluetooth::hci::RemoteNameRequestStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetEventMask(packets::PacketView<true> args) {
-  CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 8, "%s  size=%zu", __func__, args.size());
   /*
     uint64_t mask = args.begin().extract<uint64_t>();
     link_layer_controller_.SetLeEventMask(mask);
   */
-  SendCommandCompleteSuccess(OpCode::LE_SET_EVENT_MASK);
+  auto packet = bluetooth::hci::LeSetEventMaskCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeReadBufferSize(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
-          hci::Status::SUCCESS, properties_.GetLeDataPacketLength(), properties_.GetTotalNumLeDataPackets());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+
+  bluetooth::hci::LeBufferSize le_buffer_size;
+  le_buffer_size.le_data_packet_length_ = properties_.GetLeDataPacketLength();
+  le_buffer_size.total_num_le_packets_ = properties_.GetTotalNumLeDataPackets();
+
+  auto packet = bluetooth::hci::LeReadBufferSizeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, le_buffer_size);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeReadLocalSupportedFeatures(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
-          hci::Status::SUCCESS, properties_.GetLeSupportedFeatures());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet =
+      bluetooth::hci::LeReadLocalSupportedFeaturesCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+          properties_.GetLeSupportedFeatures());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetRandomAddress(packets::PacketView<true> args) {
-  CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 6, "%s  size=%zu", __func__, args.size());
   properties_.SetLeAddress(args.begin().extract<Address>());
-  SendCommandCompleteSuccess(OpCode::LE_SET_RANDOM_ADDRESS);
+  auto packet = bluetooth::hci::LeSetRandomAddressCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetAdvertisingParameters(packets::PacketView<true> args) {
-  CHECK(args.size() == 15) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 15, "%s  size=%zu", __func__, args.size());
+  auto args_itr = args.begin();
+  properties_.SetLeAdvertisingParameters(
+      args_itr.extract<uint16_t>() /* AdverisingIntervalMin */,
+      args_itr.extract<uint16_t>() /* AdverisingIntervalMax */, args_itr.extract<uint8_t>() /* AdverisingType */,
+      args_itr.extract<uint8_t>() /* OwnAddressType */, args_itr.extract<uint8_t>() /* PeerAddressType */,
+      args_itr.extract<Address>() /* PeerAddress */, args_itr.extract<uint8_t>() /* AdvertisingChannelMap */,
+      args_itr.extract<uint8_t>() /* AdvertisingFilterPolicy */
+  );
 
-  SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_PARAMETERS);
+  auto packet =
+      bluetooth::hci::LeSetAdvertisingParametersCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetAdvertisingData(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_DATA);
+  ASSERT_LOG(args.size() == 32, "%s  size=%zu", __func__, args.size());
+  properties_.SetLeAdvertisement(std::vector<uint8_t>(args.begin() + 1, args.end()));
+  auto packet = bluetooth::hci::LeSetAdvertisingDataCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetScanResponseData(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 32, "%s  size=%zu", __func__, args.size());
+  properties_.SetLeScanResponse(std::vector<uint8_t>(args.begin() + 1, args.end()));
+  auto packet = bluetooth::hci::LeSetScanResponseDataCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetAdvertisingEnable(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 1, "%s  size=%zu", __func__, args.size());
+  auto status = link_layer_controller_.SetLeAdvertisingEnable(
+      args.begin().extract<uint8_t>());
+  auto packet = bluetooth::hci::LeSetAdvertisingEnableCompleteBuilder::Create(
+      kNumCommandPackets, status);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetScanParameters(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.SetLeScanType(args[0]);
-  link_layer_controller_.SetLeScanInterval(args[1] | (args[2] << 8));
-  link_layer_controller_.SetLeScanWindow(args[3] | (args[4] << 8));
+  link_layer_controller_.SetLeScanInterval(args[1] | (args[2], 8));
+  link_layer_controller_.SetLeScanWindow(args[3] | (args[4], 8));
   link_layer_controller_.SetLeAddressType(args[5]);
   link_layer_controller_.SetLeScanFilterPolicy(args[6]);
-  SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_PARAMETERS);
+  auto packet = bluetooth::hci::LeSetScanParametersCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeSetScanEnable(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
-  LOG_INFO(LOG_TAG, "SetScanEnable: %d %d", args[0], args[1]);
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.SetLeScanEnable(args[0]);
   link_layer_controller_.SetLeFilterDuplicates(args[1]);
-  SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_ENABLE);
+  auto packet = bluetooth::hci::LeSetScanEnableCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeCreateConnection(packets::PacketView<true> args) {
-  CHECK(args.size() == 25) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 25, "%s  size=%zu", __func__, args.size());
   auto args_itr = args.begin();
   link_layer_controller_.SetLeScanInterval(args_itr.extract<uint16_t>());
   link_layer_controller_.SetLeScanWindow(args_itr.extract<uint16_t>());
@@ -840,23 +1228,29 @@
   link_layer_controller_.SetLeMinimumCeLength(args_itr.extract<uint16_t>());
   link_layer_controller_.SetLeMaximumCeLength(args_itr.extract<uint16_t>());
 
-  hci::Status status = link_layer_controller_.SetLeConnect(true);
+  auto status = link_layer_controller_.SetLeConnect(true);
 
-  SendCommandStatus(status, OpCode::LE_CREATE_CONNECTION);
+  auto packet = bluetooth::hci::LeCreateConnectionStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeConnectionUpdate(packets::PacketView<true> args) {
-  CHECK(args.size() == 14) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 14, "%s  size=%zu", __func__, args.size());
 
-  SendCommandStatus(hci::Status::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR, OpCode::LE_CONNECTION_UPDATE);
+  auto status_packet = bluetooth::hci::LeConnectionUpdateStatusBuilder::Create(
+      bluetooth::hci::ErrorCode::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR,
+      kNumCommandPackets);
+  send_event_(std::move(status_packet));
 
-  send_event_(packets::EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(hci::Status::SUCCESS, 0x0002, 0x0006,
-                                                                                 0x0000, 0x01f4)
-                  ->ToVector());
+  auto complete_packet =
+      bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create(
+          bluetooth::hci::ErrorCode::SUCCESS, 0x0002, 0x0006, 0x0000, 0x01f4);
+  send_event_(std::move(complete_packet));
 }
 
 void DualModeController::HciCreateConnection(packets::PacketView<true> args) {
-  CHECK(args.size() == 13) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 13, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   Address address = args_itr.extract<Address>();
@@ -865,150 +1259,247 @@
   uint16_t clock_offset = args_itr.extract<uint16_t>();
   uint8_t allow_role_switch = args_itr.extract<uint8_t>();
 
-  hci::Status status =
-      link_layer_controller_.CreateConnection(address, packet_type, page_scan_mode, clock_offset, allow_role_switch);
+  auto status = link_layer_controller_.CreateConnection(
+      address, packet_type, page_scan_mode, clock_offset, allow_role_switch);
 
-  SendCommandStatus(status, OpCode::CREATE_CONNECTION);
+  auto packet = bluetooth::hci::CreateConnectionStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciDisconnect(packets::PacketView<true> args) {
-  CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 3, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
   uint8_t reason = args_itr.extract<uint8_t>();
 
-  hci::Status status = link_layer_controller_.Disconnect(handle, reason);
+  auto status = link_layer_controller_.Disconnect(handle, reason);
 
-  SendCommandStatus(status, OpCode::DISCONNECT);
+  auto packet = bluetooth::hci::DisconnectStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeConnectionCancel(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.SetLeConnect(false);
-  SendCommandStatusSuccess(OpCode::LE_CREATE_CONNECTION_CANCEL);
+  auto packet = bluetooth::hci::LeCreateConnectionCancelStatusBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+  send_event_(std::move(packet));
   /* For testing Jakub's patch:  Figure out a neat way to call this without
      recompiling.  I'm thinking about a bad device. */
   /*
   SendCommandCompleteOnlyStatus(OpCode::LE_CREATE_CONNECTION_CANCEL,
-                                Status::ERR_COMMAND_DISALLOWED);
+                                bluetooth::hci::ErrorCode::COMMAND_DISALLOWED);
   */
 }
 
 void DualModeController::HciLeReadWhiteListSize(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(hci::Status::SUCCESS,
-                                                                            properties_.GetLeWhiteListSize());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::LeReadWhiteListSizeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      properties_.GetLeWhiteListSize());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeClearWhiteList(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   link_layer_controller_.LeWhiteListClear();
-  SendCommandCompleteSuccess(OpCode::LE_CLEAR_WHITE_LIST);
+  auto packet = bluetooth::hci::LeClearWhiteListCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeAddDeviceToWhiteList(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
 
   if (link_layer_controller_.LeWhiteListFull()) {
-    SendCommandCompleteOnlyStatus(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST, hci::Status::MEMORY_CAPACITY_EXCEEDED);
+    auto packet = bluetooth::hci::LeAddDeviceToWhiteListCompleteBuilder::Create(
+        kNumCommandPackets,
+        bluetooth::hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED);
+    send_event_(std::move(packet));
     return;
   }
   auto args_itr = args.begin();
   uint8_t addr_type = args_itr.extract<uint8_t>();
   Address address = args_itr.extract<Address>();
   link_layer_controller_.LeWhiteListAddDevice(address, addr_type);
-  SendCommandCompleteSuccess(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST);
+  auto packet = bluetooth::hci::LeAddDeviceToWhiteListCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeRemoveDeviceFromWhiteList(packets::PacketView<true> args) {
-  CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   uint8_t addr_type = args_itr.extract<uint8_t>();
   Address address = args_itr.extract<Address>();
   link_layer_controller_.LeWhiteListRemoveDevice(address, addr_type);
-  SendCommandCompleteSuccess(OpCode::LE_REMOVE_DEVICE_FROM_WHITE_LIST);
+  auto packet =
+      bluetooth::hci::LeRemoveDeviceFromWhiteListCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
 
-/*
-void DualModeController::HciLeReadRemoteUsedFeaturesRsp(uint16_t handle,
-                                                        uint64_t features) {
-  std::shared_ptr<packets::EventPacketBuilder> event =
-      packets::EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(
-          hci::Status::SUCCESS, handle, features);
-  send_event_(event->ToVector());
+void DualModeController::HciLeClearResolvingList(
+    packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  link_layer_controller_.LeResolvingListClear();
+  auto packet = bluetooth::hci::LeClearResolvingListCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
 }
-*/
+
+void DualModeController::HciLeAddDeviceToResolvingList(
+    packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 39, "%s  size=%zu", __func__, args.size());
+
+  if (link_layer_controller_.LeResolvingListFull()) {
+    auto packet =
+        bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
+            kNumCommandPackets,
+            bluetooth::hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED);
+    send_event_(std::move(packet));
+    return;
+  }
+  auto args_itr = args.begin();
+  uint8_t addr_type = args_itr.extract<uint8_t>();
+  Address address = args_itr.extract<Address>();
+  std::array<uint8_t, LinkLayerController::kIrk_size> peerIrk;
+  std::array<uint8_t, LinkLayerController::kIrk_size> localIrk;
+  for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size;
+       irk_ind++) {
+    peerIrk[irk_ind] = args_itr.extract<uint8_t>();
+  }
+
+  for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size;
+       irk_ind++) {
+    localIrk[irk_ind] = args_itr.extract<uint8_t>();
+  }
+
+  link_layer_controller_.LeResolvingListAddDevice(address, addr_type, peerIrk,
+                                                  localIrk);
+  auto packet =
+      bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeRemoveDeviceFromResolvingList(
+    packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 7, "%s  size=%zu", __func__, args.size());
+
+  auto args_itr = args.begin();
+  uint8_t addr_type = args_itr.extract<uint8_t>();
+  Address address = args_itr.extract<Address>();
+  link_layer_controller_.LeResolvingListRemoveDevice(address, addr_type);
+  auto packet =
+      bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create(
+          kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetPrivacyMode(packets::PacketView<true> args) {
+  ASSERT_LOG(args.size() == 8, "%s  size=%zu", __func__, args.size());
+
+  auto args_itr = args.begin();
+  uint8_t peer_identity_address_type = args_itr.extract<uint8_t>();
+  Address peer_identity_address = args_itr.extract<Address>();
+  uint8_t privacy_mode = args_itr.extract<uint8_t>();
+
+  if (link_layer_controller_.LeResolvingListContainsDevice(
+          peer_identity_address, peer_identity_address_type)) {
+    link_layer_controller_.LeSetPrivacyMode(
+        peer_identity_address_type, peer_identity_address, privacy_mode);
+  }
+
+  auto packet = bluetooth::hci::LeSetPrivacyModeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
 
 void DualModeController::HciLeReadRemoteFeatures(packets::PacketView<true> args) {
-  CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 2, "%s  size=%zu", __func__, args.size());
 
   uint16_t handle = args.begin().extract<uint16_t>();
 
-  hci::Status status =
-      link_layer_controller_.SendCommandToRemoteByHandle(OpCode::LE_READ_REMOTE_FEATURES, args, handle);
+  auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode::LE_READ_REMOTE_FEATURES, args, handle);
 
-  SendCommandStatus(status, OpCode::LE_READ_REMOTE_FEATURES);
+  auto packet = bluetooth::hci::LeConnectionUpdateStatusBuilder::Create(
+      status, kNumCommandPackets);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeRand(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   uint64_t random_val = 0;
   for (size_t rand_bytes = 0; rand_bytes < sizeof(uint64_t); rand_bytes += sizeof(RAND_MAX)) {
     random_val = (random_val << (8 * sizeof(RAND_MAX))) | random();
   }
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status::SUCCESS, random_val);
-  send_event_(command_complete->ToVector());
+
+  auto packet = bluetooth::hci::LeRandCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, random_val);
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeReadSupportedStates(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status::SUCCESS,
-                                                                              properties_.GetLeSupportedStates());
-  send_event_(command_complete->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::LeReadSupportedStatesCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      properties_.GetLeSupportedStates());
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeVendorCap(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 0, "%s  size=%zu", __func__, args.size());
   vector<uint8_t> caps = properties_.GetLeVendorCap();
   if (caps.size() == 0) {
-    SendCommandCompleteOnlyStatus(OpCode::LE_GET_VENDOR_CAPABILITIES, hci::Status::UNKNOWN_COMMAND);
+    SendCommandCompleteUnknownOpCodeEvent(static_cast<uint16_t>(
+        bluetooth::hci::OpCode::LE_GET_VENDOR_CAPABILITIES));
     return;
   }
 
-  std::shared_ptr<packets::EventPacketBuilder> command_complete =
-      packets::EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(hci::Status::SUCCESS,
-                                                                                properties_.GetLeVendorCap());
-  send_event_(command_complete->ToVector());
+  std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+      std::make_unique<bluetooth::packet::RawBuilder>();
+  raw_builder_ptr->AddOctets1(
+      static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS));
+  raw_builder_ptr->AddOctets(properties_.GetLeVendorCap());
+
+  auto packet = bluetooth::hci::CommandCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::OpCode::LE_GET_VENDOR_CAPABILITIES,
+      std::move(raw_builder_ptr));
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciLeVendorMultiAdv(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteOnlyStatus(OpCode::LE_MULTI_ADVT, hci::Status::UNKNOWN_COMMAND);
+  ASSERT(args.size() > 0);
+  SendCommandCompleteUnknownOpCodeEvent(
+      static_cast<uint16_t>(bluetooth::hci::OpCode::LE_MULTI_ADVT));
 }
 
 void DualModeController::HciLeAdvertisingFilter(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteOnlyStatus(OpCode::LE_ADV_FILTER, hci::Status::UNKNOWN_COMMAND);
+  ASSERT(args.size() > 0);
+  SendCommandCompleteUnknownOpCodeEvent(
+      static_cast<uint16_t>(bluetooth::hci::OpCode::LE_ADV_FILTER));
 }
 
 void DualModeController::HciLeEnergyInfo(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteOnlyStatus(OpCode::LE_ENERGY_INFO, hci::Status::UNKNOWN_COMMAND);
+  ASSERT(args.size() > 0);
+  SendCommandCompleteUnknownOpCodeEvent(
+      static_cast<uint16_t>(bluetooth::hci::OpCode::LE_ENERGY_INFO));
 }
 
 void DualModeController::HciLeExtendedScanParams(packets::PacketView<true> args) {
-  CHECK(args.size() > 0);
-  SendCommandCompleteOnlyStatus(OpCode::LE_EXTENDED_SCAN_PARAMS, hci::Status::UNKNOWN_COMMAND);
+  ASSERT(args.size() > 0);
+  SendCommandCompleteUnknownOpCodeEvent(
+      static_cast<uint16_t>(bluetooth::hci::OpCode::LE_EXTENDED_SCAN_PARAMS));
 }
 
 void DualModeController::HciLeStartEncryption(packets::PacketView<true> args) {
-  CHECK(args.size() == 28) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 28, "%s  size=%zu", __func__, args.size());
 
   auto args_itr = args.begin();
   uint16_t handle = args_itr.extract<uint16_t>();
@@ -1018,9 +1509,14 @@
   // for (size_t i = 0; i < 16; i++) {
   //   long_term_key.push_back(args_itr.extract<uint18_t>();
   // }
-  SendCommandStatus(hci::Status::SUCCESS, OpCode::LE_START_ENCRYPTION);
+  auto status_packet = bluetooth::hci::LeStartEncryptionStatusBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+  send_event_(std::move(status_packet));
 
-  send_event_(packets::EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 0x01)->ToVector());
+  auto complete_packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle,
+      bluetooth::hci::EncryptionEnabled::OFF);
+  send_event_(std::move(complete_packet));
 #if 0
 
   std::shared_ptr<packets::AclPacketBuilder> encryption_information =
@@ -1076,25 +1572,35 @@
 }
 
 void DualModeController::HciReadLoopbackMode(packets::PacketView<true> args) {
-  CHECK(args.size() == 0) << __func__ << " size=" << args.size();
-  send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status::SUCCESS, loopback_mode_)
-                  ->ToVector());
+  ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+  auto packet = bluetooth::hci::ReadLoopbackModeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+      static_cast<bluetooth::hci::LoopbackMode>(loopback_mode_));
+  send_event_(std::move(packet));
 }
 
 void DualModeController::HciWriteLoopbackMode(packets::PacketView<true> args) {
-  CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+  ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
   loopback_mode_ = static_cast<hci::LoopbackMode>(args[0]);
   // ACL channel
   uint16_t acl_handle = 0x123;
-  send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
-                  hci::Status::SUCCESS, acl_handle, properties_.GetAddress(), hci::LinkType::ACL, false)
-                  ->ToVector());
+  auto packet_acl = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, acl_handle, properties_.GetAddress(),
+      bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet_acl));
   // SCO channel
   uint16_t sco_handle = 0x345;
-  send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
-                  hci::Status::SUCCESS, sco_handle, properties_.GetAddress(), hci::LinkType::SCO, false)
-                  ->ToVector());
-  SendCommandCompleteSuccess(OpCode::WRITE_LOOPBACK_MODE);
+  auto packet_sco = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, sco_handle, properties_.GetAddress(),
+      bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet_sco));
+  auto packet = bluetooth::hci::WriteLoopbackModeCompleteBuilder::Create(
+      kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+  send_event_(std::move(packet));
+}
+
+void DualModeController::SetAddress(Address address) {
+  properties_.SetAddress(address);
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
index f33bbb8..bd9c17d 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
@@ -24,14 +24,17 @@
 #include <vector>
 
 #include "base/time/time.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
 #include "link_layer_controller.h"
 #include "model/devices/device.h"
 #include "model/setup/async_manager.h"
 #include "security_manager.h"
-#include "types/address.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 // Emulates a dual mode BR/EDR + LE controller by maintaining the link layer
 // state machine detailed in the Bluetooth Core Specification Version 4.2,
 // Volume 6, Part B, Section 1.1 (page 30). Provides methods corresponding to
@@ -60,17 +63,16 @@
 
   virtual std::string GetTypeString() const override;
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView incoming) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView incoming) override;
 
   virtual void TimerTick() override;
 
-  // Send packets to remote devices
-  void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type);
-
   // Route commands and data from the stack.
   void HandleAcl(std::shared_ptr<std::vector<uint8_t>> acl_packet);
   void HandleCommand(std::shared_ptr<std::vector<uint8_t>> command_packet);
   void HandleSco(std::shared_ptr<std::vector<uint8_t>> sco_packet);
+  void HandleIso(std::shared_ptr<std::vector<uint8_t>> iso_packet);
 
   // Set the callbacks for scheduling tasks.
   void RegisterTaskScheduler(std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> evtScheduler);
@@ -82,12 +84,21 @@
   void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
 
   // Set the callbacks for sending packets to the HCI.
-  void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+  void RegisterEventChannel(
+      const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+          send_event);
 
   void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
 
   void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
 
+  void RegisterIsoChannel(
+      const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+          send_iso);
+
+  // Set the device's address.
+  void SetAddress(Address address) override;
+
   // Controller commands. For error codes, see the Bluetooth Core Specification,
   // Version 4.2, Volume 2, Part D (page 370).
 
@@ -127,9 +138,18 @@
   // 7.1.16
   void HciSetConnectionEncryption(packets::PacketView<true> args);
 
+  // 7.1.17
+  void HciChangeConnectionLinkKey(packets::PacketView<true> args);
+
+  // 7.1.18
+  void HciMasterLinkKey(packets::PacketView<true> args);
+
   // 7.1.19
   void HciRemoteNameRequest(packets::PacketView<true> args);
 
+  // 7.2.8
+  void HciSwitchRole(packets::PacketView<true> args);
+
   // 7.1.21
   void HciReadRemoteSupportedFeatures(packets::PacketView<true> args);
 
@@ -169,12 +189,27 @@
   // Link Policy Commands
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2
 
+  // 7.2.1
+  void HciHoldMode(packets::PacketView<true> args);
+
+  // 7.2.2
+  void HciSniffMode(packets::PacketView<true> args);
+
+  // 7.2.3
+  void HciExitSniffMode(packets::PacketView<true> args);
+
+  // 7.2.6
+  void HciQosSetup(packets::PacketView<true> args);
+
   // 7.2.10
   void HciWriteLinkPolicySettings(packets::PacketView<true> args);
 
   // 7.2.12
   void HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args);
 
+  // 7.2.13
+  void HciFlowSpecification(packets::PacketView<true> args);
+
   // 7.2.14
   void HciSniffSubrating(packets::PacketView<true> args);
 
@@ -241,12 +276,18 @@
   // 7.3.56
   void HciWriteExtendedInquiryResponse(packets::PacketView<true> args);
 
+  // 7.3.57
+  void HciRefreshEncryptionKey(packets::PacketView<true> args);
+
   // 7.3.59
   void HciWriteSimplePairingMode(packets::PacketView<true> args);
 
   // 7.3.79
   void HciWriteLeHostSupport(packets::PacketView<true> args);
 
+  // 7.3.92
+  void HciWriteSecureConnectionsHostSupport(packets::PacketView<true> args);
+
   // Informational Parameters Commands
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4
 
@@ -262,6 +303,9 @@
   // 7.4.2
   void HciReadLocalSupportedCommands(packets::PacketView<true> args);
 
+  // 7.4.3
+  void HciReadLocalSupportedFeatures(packets::PacketView<true> args);
+
   // 7.4.4
   void HciReadLocalExtendedFeatures(packets::PacketView<true> args);
 
@@ -271,6 +315,9 @@
   // Status Parameters Commands
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.5
 
+  // 7.5.7
+  void HciReadEncryptionKeySize(packets::PacketView<true> args);
+
   // Test Commands
   // Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7
 
@@ -301,6 +348,12 @@
   // 7.8.7
   void HciLeSetAdvertisingData(packets::PacketView<true> args);
 
+  // 7.8.8
+  void HciLeSetScanResponseData(packets::PacketView<true> args);
+
+  // 7.8.9
+  void HciLeSetAdvertisingEnable(packets::PacketView<true> args);
+
   // 7.8.10
   void HciLeSetScanParameters(packets::PacketView<true> args);
 
@@ -340,6 +393,18 @@
   // 7.8.27
   void HciLeReadSupportedStates(packets::PacketView<true> args);
 
+  // 7.8.38
+  void HciLeAddDeviceToResolvingList(packets::PacketView<true> args);
+
+  // 7.8.39
+  void HciLeRemoveDeviceFromResolvingList(packets::PacketView<true> args);
+
+  // 7.8.40
+  void HciLeClearResolvingList(packets::PacketView<true> args);
+
+  // 7.8.77
+  void HciLeSetPrivacyMode(packets::PacketView<true> args);
+
   // Vendor-specific Commands
 
   void HciLeVendorSleepMode(packets::PacketView<true> args);
@@ -367,27 +432,15 @@
   // Creates a command complete event and sends it back to the HCI.
   void SendCommandComplete(hci::OpCode command_opcode, const std::vector<uint8_t>& return_parameters) const;
 
-  // Sends a command complete event with no return parameters.
-  void SendCommandCompleteSuccess(hci::OpCode command_opcode) const;
-
   void SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const;
 
-  // Sends a command complete event with no return parameters.
-  void SendCommandCompleteOnlyStatus(hci::OpCode command_opcode, hci::Status status) const;
-
-  void SendCommandCompleteStatusAndAddress(hci::OpCode command_opcode, hci::Status status,
-                                           const Address& address) const;
-
-  // Creates a command status event and sends it back to the HCI.
-  void SendCommandStatus(hci::Status status, hci::OpCode command_opcode) const;
-
-  // Sends a command status event with default event parameters.
-  void SendCommandStatusSuccess(hci::OpCode command_opcode) const;
-
   // Callbacks to send packets back to the HCI.
-  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
-  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+  std::function<void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>
+      send_acl_;
+  std::function<void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>
+      send_event_;
   std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_iso_;
 
   // Maintains the commands to be registered and used in the HciHandler object.
   // Keys are command opcodes and values are the callbacks to handle each
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
index 1ee30f5..aebe621 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
@@ -14,30 +14,15 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "link_layer_controller"
-
 #include "link_layer_controller.h"
 
-#include <base/logging.h>
-
 #include "hci.h"
-#include "osi/include/log.h"
-#include "packets/hci/acl_packet_builder.h"
+#include "include/le_advertisement.h"
+#include "os/log.h"
 #include "packets/hci/command_packet_view.h"
-#include "packets/hci/event_packet_builder.h"
-#include "packets/hci/sco_packet_builder.h"
-#include "packets/link_layer/command_builder.h"
-#include "packets/link_layer/command_view.h"
-#include "packets/link_layer/disconnect_view.h"
-#include "packets/link_layer/encrypt_connection_view.h"
-#include "packets/link_layer/inquiry_response_view.h"
-#include "packets/link_layer/inquiry_view.h"
-#include "packets/link_layer/io_capability_view.h"
-#include "packets/link_layer/le_advertisement_view.h"
-#include "packets/link_layer/page_reject_view.h"
-#include "packets/link_layer/page_response_view.h"
-#include "packets/link_layer/page_view.h"
-#include "packets/link_layer/response_view.h"
+#include "packets/raw_builder.h"
+
+#include "packet/raw_builder.h"
 
 using std::vector;
 using namespace std::chrono;
@@ -45,6 +30,8 @@
 
 namespace test_vendor_lib {
 
+constexpr uint16_t kNumCommandPackets = 0x01;
+
 // TODO: Model Rssi?
 static uint8_t GetRssi() {
   static uint8_t rssi = 0;
@@ -55,70 +42,129 @@
   return -(rssi);
 }
 
-void LinkLayerController::SendLELinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
-  if (schedule_task_) {
-    schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::LOW_ENERGY); });
-  } else {
-    send_to_remote_(packet, Phy::Type::LOW_ENERGY);
-  }
+void LinkLayerController::SendLeLinkLayerPacket(
+    std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) {
+  std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet =
+      std::move(packet);
+  ScheduleTask(milliseconds(50), [this, shared_packet]() {
+    send_to_remote_(std::move(shared_packet), Phy::Type::LOW_ENERGY);
+  });
 }
 
-void LinkLayerController::SendLinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
-  if (schedule_task_) {
-    schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::BR_EDR); });
-  } else {
-    send_to_remote_(packet, Phy::Type::BR_EDR);
-  }
+void LinkLayerController::SendLinkLayerPacket(
+    std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) {
+  std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet =
+      std::move(packet);
+  ScheduleTask(milliseconds(50), [this, shared_packet]() {
+    send_to_remote_(std::move(shared_packet), Phy::Type::BR_EDR);
+  });
 }
 
-hci::Status LinkLayerController::SendCommandToRemoteByAddress(hci::OpCode opcode, PacketView<true> args,
-                                                              const Address& remote, bool use_public_address) {
-  std::shared_ptr<LinkLayerPacketBuilder> command;
-  Address local_address;
-  if (use_public_address) {
-    local_address = properties_.GetAddress();
-  } else {
-    local_address = properties_.GetLeAddress();
+bluetooth::hci::ErrorCode LinkLayerController::SendCommandToRemoteByAddress(
+    bluetooth::hci::OpCode opcode, PacketView<true> args,
+    const Address& remote) {
+  Address local_address = properties_.GetAddress();
+
+  switch (opcode) {
+    case (bluetooth::hci::OpCode::REMOTE_NAME_REQUEST):
+      // LMP features get requested with remote name requests.
+      SendLinkLayerPacket(model::packets::ReadRemoteLmpFeaturesBuilder::Create(
+          local_address, remote));
+      SendLinkLayerPacket(model::packets::RemoteNameRequestBuilder::Create(
+          local_address, remote));
+      break;
+    case (bluetooth::hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES):
+      SendLinkLayerPacket(
+          model::packets::ReadRemoteSupportedFeaturesBuilder::Create(
+              local_address, remote));
+      break;
+    case (bluetooth::hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
+      uint8_t page_number =
+          (args.begin() + 2).extract<uint8_t>();  // skip the handle
+      SendLinkLayerPacket(
+          model::packets::ReadRemoteExtendedFeaturesBuilder::Create(
+              local_address, remote, page_number));
+    } break;
+    case (bluetooth::hci::OpCode::READ_REMOTE_VERSION_INFORMATION):
+      SendLinkLayerPacket(
+          model::packets::ReadRemoteVersionInformationBuilder::Create(
+              local_address, remote));
+      break;
+    case (bluetooth::hci::OpCode::READ_CLOCK_OFFSET):
+      SendLinkLayerPacket(model::packets::ReadClockOffsetBuilder::Create(
+          local_address, remote));
+      break;
+    default:
+      LOG_INFO("Dropping unhandled command 0x%04x",
+               static_cast<uint16_t>(opcode));
+      return bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND;
   }
-  command = LinkLayerPacketBuilder::WrapCommand(CommandBuilder::Create(static_cast<uint16_t>(opcode), args),
-                                                local_address, remote);
-  SendLinkLayerPacket(std::move(command));
-  return hci::Status::SUCCESS;
+
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::SendCommandToRemoteByHandle(hci::OpCode opcode, PacketView<true> args,
-                                                             uint16_t handle) {
+bluetooth::hci::ErrorCode LinkLayerController::SendCommandToRemoteByHandle(
+    bluetooth::hci::OpCode opcode, PacketView<true> args, uint16_t handle) {
   // TODO: Handle LE connections
-  bool use_public_address = true;
-  if (!classic_connections_.HasHandle(handle)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
-  return SendCommandToRemoteByAddress(opcode, args, classic_connections_.GetAddress(handle), use_public_address);
+  return SendCommandToRemoteByAddress(opcode, args,
+                                      connections_.GetAddress(handle));
 }
 
-hci::Status LinkLayerController::SendAclToRemote(AclPacketView acl_packet) {
-  // TODO: Handle LE connections
+hci::Status LinkLayerController::SendAclToRemote(
+    bluetooth::hci::AclPacketView acl_packet) {
   uint16_t handle = acl_packet.GetHandle();
-  if (!classic_connections_.HasHandle(handle)) {
+  if (!connections_.HasHandle(handle)) {
     return hci::Status::UNKNOWN_CONNECTION;
   }
 
-  std::unique_ptr<ViewForwarderBuilder> acl_builder = ViewForwarderBuilder::Create(acl_packet);
+  Address my_address = properties_.GetAddress();
+  Address destination = connections_.GetAddress(handle);
+  if (connections_.GetOwnAddressType(handle) != 0) {  // If it's not public, it must be LE
+    my_address = properties_.GetLeAddress();
+  }
 
-  std::shared_ptr<LinkLayerPacketBuilder> acl = LinkLayerPacketBuilder::WrapAcl(
-      std::move(acl_builder), properties_.GetAddress(), classic_connections_.GetAddress(handle));
-
-  LOG_INFO(LOG_TAG, "%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle,
+  LOG_INFO("%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle,
            static_cast<int>(acl_packet.size()));
 
-  schedule_task_(milliseconds(5), [this, handle]() {
-    send_event_(EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+  ScheduleTask(milliseconds(5), [this, handle]() {
+    std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+    bluetooth::hci::CompletedPackets cp;
+    cp.connection_handle_ = handle;
+    cp.host_num_of_completed_packets_ = kNumCommandPackets;
+    completed_packets.push_back(cp);
+    auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+        completed_packets);
+    send_event_(std::move(packet));
   });
-  SendLinkLayerPacket(acl);
+
+  auto acl_payload = acl_packet.GetPayload();
+
+  std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+      std::make_unique<bluetooth::packet::RawBuilder>();
+  std::vector<uint8_t> payload_bytes(acl_payload.begin(), acl_payload.end());
+
+  uint16_t first_two_bytes =
+      static_cast<uint16_t>(acl_packet.GetHandle()) +
+      (static_cast<uint16_t>(acl_packet.GetPacketBoundaryFlag()) << 12) +
+      (static_cast<uint16_t>(acl_packet.GetBroadcastFlag()) << 14);
+  raw_builder_ptr->AddOctets2(first_two_bytes);
+  raw_builder_ptr->AddOctets2(static_cast<uint16_t>(payload_bytes.size()));
+  raw_builder_ptr->AddOctets(payload_bytes);
+
+  auto acl = model::packets::AclPacketBuilder::Create(
+      my_address, destination, std::move(raw_builder_ptr));
+
+  SendLinkLayerPacket(std::move(acl));
   return hci::Status::SUCCESS;
 }
 
-void LinkLayerController::IncomingPacket(LinkLayerPacketView incoming) {
+void LinkLayerController::IncomingPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  ASSERT(incoming.IsValid());
+
   // TODO: Resolvable private addresses?
   if (incoming.GetDestinationAddress() != properties_.GetAddress() &&
       incoming.GetDestinationAddress() != properties_.GetLeAddress() &&
@@ -128,282 +174,480 @@
   }
 
   switch (incoming.GetType()) {
-    case Link::PacketType::ACL:
+    case model::packets::PacketType::ACL:
       IncomingAclPacket(incoming);
       break;
-    case Link::PacketType::COMMAND:
-      IncomingCommandPacket(incoming);
-      break;
-    case Link::PacketType::DISCONNECT:
+    case model::packets::PacketType::DISCONNECT:
       IncomingDisconnectPacket(incoming);
       break;
-    case Link::PacketType::ENCRYPT_CONNECTION:
+    case model::packets::PacketType::ENCRYPT_CONNECTION:
       IncomingEncryptConnection(incoming);
       break;
-    case Link::PacketType::ENCRYPT_CONNECTION_RESPONSE:
+    case model::packets::PacketType::ENCRYPT_CONNECTION_RESPONSE:
       IncomingEncryptConnectionResponse(incoming);
       break;
-    case Link::PacketType::INQUIRY:
+    case model::packets::PacketType::INQUIRY:
       if (inquiry_scans_enabled_) {
         IncomingInquiryPacket(incoming);
       }
       break;
-    case Link::PacketType::INQUIRY_RESPONSE:
+    case model::packets::PacketType::INQUIRY_RESPONSE:
       IncomingInquiryResponsePacket(incoming);
       break;
-    case Link::PacketType::IO_CAPABILITY_REQUEST:
+    case model::packets::PacketType::IO_CAPABILITY_REQUEST:
       IncomingIoCapabilityRequestPacket(incoming);
       break;
-    case Link::PacketType::IO_CAPABILITY_RESPONSE:
+    case model::packets::PacketType::IO_CAPABILITY_RESPONSE:
       IncomingIoCapabilityResponsePacket(incoming);
       break;
-    case Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE:
+    case model::packets::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE:
       IncomingIoCapabilityNegativeResponsePacket(incoming);
       break;
-    case Link::PacketType::LE_ADVERTISEMENT:
+    case model::packets::PacketType::LE_ADVERTISEMENT:
       if (le_scan_enable_ || le_connect_) {
         IncomingLeAdvertisementPacket(incoming);
       }
       break;
-    case Link::PacketType::LE_SCAN:
+    case model::packets::PacketType::LE_CONNECT:
+      IncomingLeConnectPacket(incoming);
+      break;
+    case model::packets::PacketType::LE_CONNECT_COMPLETE:
+      IncomingLeConnectCompletePacket(incoming);
+      break;
+    case model::packets::PacketType::LE_SCAN:
       // TODO: Check Advertising flags and see if we are scannable.
       IncomingLeScanPacket(incoming);
       break;
-    case Link::PacketType::LE_SCAN_RESPONSE:
+    case model::packets::PacketType::LE_SCAN_RESPONSE:
       if (le_scan_enable_ && le_scan_type_ == 1) {
         IncomingLeScanResponsePacket(incoming);
       }
       break;
-    case Link::PacketType::PAGE:
+    case model::packets::PacketType::PAGE:
       if (page_scans_enabled_) {
         IncomingPagePacket(incoming);
       }
       break;
-    case Link::PacketType::PAGE_REJECT:
-      IncomingPageRejectPacket(incoming);
-      break;
-    case Link::PacketType::PAGE_RESPONSE:
+    case model::packets::PacketType::PAGE_RESPONSE:
       IncomingPageResponsePacket(incoming);
       break;
-    case Link::PacketType::RESPONSE:
-      IncomingResponsePacket(incoming);
+    case model::packets::PacketType::PAGE_REJECT:
+      IncomingPageRejectPacket(incoming);
+      break;
+    case (model::packets::PacketType::REMOTE_NAME_REQUEST):
+      IncomingRemoteNameRequest(incoming);
+      break;
+    case (model::packets::PacketType::REMOTE_NAME_REQUEST_RESPONSE):
+      IncomingRemoteNameRequestResponse(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES):
+      IncomingReadRemoteSupportedFeatures(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES_RESPONSE):
+      IncomingReadRemoteSupportedFeaturesResponse(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES):
+      IncomingReadRemoteLmpFeatures(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES_RESPONSE):
+      IncomingReadRemoteLmpFeaturesResponse(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES):
+      IncomingReadRemoteExtendedFeatures(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES_RESPONSE):
+      IncomingReadRemoteExtendedFeaturesResponse(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION):
+      IncomingReadRemoteVersion(incoming);
+      break;
+    case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE):
+      IncomingReadRemoteVersionResponse(incoming);
+      break;
+    case (model::packets::PacketType::READ_CLOCK_OFFSET):
+      IncomingReadClockOffset(incoming);
+      break;
+    case (model::packets::PacketType::READ_CLOCK_OFFSET_RESPONSE):
+      IncomingReadClockOffsetResponse(incoming);
       break;
     default:
-      LOG_WARN(LOG_TAG, "Dropping unhandled packet of type %d", static_cast<int32_t>(incoming.GetType()));
+      LOG_WARN("Dropping unhandled packet of type %s",
+               model::packets::PacketTypeText(incoming.GetType()).c_str());
   }
 }
 
-void LinkLayerController::IncomingAclPacket(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(),
+void LinkLayerController::IncomingAclPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(),
            incoming.GetDestinationAddress().ToString().c_str());
-  AclPacketView acl_view = AclPacketView::Create(incoming.GetPayload());
-  LOG_INFO(LOG_TAG, "%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(),
-           static_cast<int>(acl_view.size()));
-  uint16_t local_handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
-  LOG_INFO(LOG_TAG, "%s: local handle 0x%x", __func__, local_handle);
 
-  acl::PacketBoundaryFlagsType boundary_flags = acl_view.GetPacketBoundaryFlags();
-  acl::BroadcastFlagsType broadcast_flags = acl_view.GetBroadcastFlags();
-  std::unique_ptr<ViewForwarderBuilder> builder = ViewForwarderBuilder::Create(acl_view.GetPayload());
-  std::unique_ptr<AclPacketBuilder> local_acl =
-      AclPacketBuilder::Create(local_handle, boundary_flags, broadcast_flags, std::move(builder));
-  send_acl_(local_acl->ToVector());
+  auto acl = model::packets::AclPacketView::Create(incoming);
+  ASSERT(acl.IsValid());
+  auto payload = acl.GetPayload();
+  std::shared_ptr<std::vector<uint8_t>> payload_bytes =
+      std::make_shared<std::vector<uint8_t>>(payload.begin(), payload.end());
+
+  bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(
+      payload_bytes);
+  auto acl_view = bluetooth::hci::AclPacketView::Create(raw_packet);
+  ASSERT(acl_view.IsValid());
+
+  LOG_INFO("%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(), static_cast<int>(acl_view.size()));
+  uint16_t local_handle = connections_.GetHandle(incoming.GetSourceAddress());
+  LOG_INFO("%s: local handle 0x%x", __func__, local_handle);
+
+  std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+      std::make_unique<bluetooth::packet::RawBuilder>();
+  std::vector<uint8_t> payload_data(acl_view.GetPayload().begin(),
+                                    acl_view.GetPayload().end());
+  raw_builder_ptr->AddOctets(payload_data);
+
+  auto acl_packet = bluetooth::hci::AclPacketBuilder::Create(
+      local_handle, acl_view.GetPacketBoundaryFlag(),
+      acl_view.GetBroadcastFlag(), std::move(raw_builder_ptr));
+
+  send_acl_(std::move(acl_packet));
 }
 
-void LinkLayerController::IncomingCommandPacket(LinkLayerPacketView incoming) {
-  // TODO: Check the destination address to see if this packet is for me.
-  CommandView command = CommandView::GetCommand(incoming);
-  hci::OpCode opcode = static_cast<hci::OpCode>(command.GetOpcode());
-  auto args = command.GetData();
-  std::vector<uint64_t> response_data;
+void LinkLayerController::IncomingRemoteNameRequest(
+    model::packets::LinkLayerPacketView packet) {
+  auto view = model::packets::RemoteNameRequestView::Create(packet);
+  ASSERT(view.IsValid());
 
-  switch (opcode) {
-    case (hci::OpCode::REMOTE_NAME_REQUEST): {
-      std::vector<uint8_t> name = properties_.GetName();
-      LOG_INFO(LOG_TAG, "Remote Name (Local Name) %d", static_cast<int>(name.size()));
-      response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
-      response_data.push_back(name.size());
-      uint64_t word = 0;
-      for (size_t i = 0; i < name.size(); i++) {
-        if (i > 0 && (i % 8 == 0)) {
-          response_data.push_back(word);
-          word = 0;
-        }
-        word |= static_cast<uint64_t>(name[i]) << (8 * (i % 8));
-      }
-      response_data.push_back(word);
-    } break;
-    case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES):
-      LOG_INFO(LOG_TAG, "(%s) Remote Supported Features Requested by: %s %x",
-               incoming.GetDestinationAddress().ToString().c_str(), incoming.GetSourceAddress().ToString().c_str(),
-               static_cast<int>(properties_.GetSupportedFeatures()));
-      response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
-      response_data.push_back(properties_.GetSupportedFeatures());
-      break;
-    case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
-      uint8_t page_number = (args + 2).extract<uint8_t>();  // skip the handle
-      LOG_INFO(LOG_TAG, "(%s) Remote Extended Features %d Requested by: %s",
-               incoming.GetDestinationAddress().ToString().c_str(), page_number,
-               incoming.GetSourceAddress().ToString().c_str());
-      uint8_t max_page_number = properties_.GetExtendedFeaturesMaximumPageNumber();
-      if (page_number > max_page_number) {
-        response_data.push_back(static_cast<uint8_t>(hci::Status::INVALID_HCI_COMMAND_PARAMETERS));
-        response_data.push_back(page_number);
-        response_data.push_back(max_page_number);
-        response_data.push_back(0);
-      } else {
-        response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
-        response_data.push_back(page_number);
-        response_data.push_back(max_page_number);
-        response_data.push_back(properties_.GetExtendedFeatures(page_number));
-      }
-    } break;
-    case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION):
-      response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
-      response_data.push_back(properties_.GetLmpPalVersion());
-      response_data.push_back(properties_.GetManufacturerName());
-      response_data.push_back(properties_.GetLmpPalSubversion());
-      break;
-    case (hci::OpCode::READ_CLOCK_OFFSET):
-      response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
-      response_data.push_back(properties_.GetClockOffset());
-      break;
-    default:
-      LOG_INFO(LOG_TAG, "Dropping unhandled command 0x%04x", static_cast<uint16_t>(opcode));
-      return;
+  SendLinkLayerPacket(model::packets::RemoteNameRequestResponseBuilder::Create(
+      packet.GetDestinationAddress(), packet.GetSourceAddress(),
+      properties_.GetName()));
+}
+
+void LinkLayerController::IncomingRemoteNameRequestResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view = model::packets::RemoteNameRequestResponseView::Create(packet);
+  ASSERT(view.IsValid());
+
+  send_event_(bluetooth::hci::RemoteNameRequestCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, packet.GetSourceAddress(),
+      view.GetName()));
+}
+
+void LinkLayerController::IncomingReadRemoteLmpFeatures(
+    model::packets::LinkLayerPacketView packet) {
+  SendLinkLayerPacket(
+      model::packets::ReadRemoteLmpFeaturesResponseBuilder::Create(
+          packet.GetDestinationAddress(), packet.GetSourceAddress(),
+          properties_.GetExtendedFeatures(1)));
+}
+
+void LinkLayerController::IncomingReadRemoteLmpFeaturesResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view = model::packets::ReadRemoteLmpFeaturesResponseView::Create(packet);
+  ASSERT(view.IsValid());
+  send_event_(
+      bluetooth::hci::RemoteHostSupportedFeaturesNotificationBuilder::Create(
+          packet.GetSourceAddress(), view.GetFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteSupportedFeatures(
+    model::packets::LinkLayerPacketView packet) {
+  SendLinkLayerPacket(
+      model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create(
+          packet.GetDestinationAddress(), packet.GetSourceAddress(),
+          properties_.GetSupportedFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteSupportedFeaturesResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view =
+      model::packets::ReadRemoteSupportedFeaturesResponseView::Create(packet);
+  ASSERT(view.IsValid());
+  Address source = packet.GetSourceAddress();
+  if (connections_.IsDeviceConnected(source)) {
+    uint16_t handle = connections_.GetHandle(source);
+    send_event_(
+        bluetooth::hci::ReadRemoteSupportedFeaturesCompleteBuilder::Create(
+            bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetFeatures()));
+  } else {
+    LOG_INFO("Discarding response from a disconnected device %s",
+             source.ToString().c_str());
+  }
+}
+
+void LinkLayerController::IncomingReadRemoteExtendedFeatures(
+    model::packets::LinkLayerPacketView packet) {
+  auto view = model::packets::ReadRemoteExtendedFeaturesView::Create(packet);
+  ASSERT(view.IsValid());
+  uint8_t page_number = view.GetPageNumber();
+  uint8_t error_code = static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS);
+  if (page_number > properties_.GetExtendedFeaturesMaximumPageNumber()) {
+    error_code = static_cast<uint8_t>(
+        bluetooth::hci::ErrorCode::INVALID_LMP_OR_LL_PARAMETERS);
   }
   SendLinkLayerPacket(
-      LinkLayerPacketBuilder::WrapResponse(ResponseBuilder::Create(static_cast<uint16_t>(opcode), response_data),
-                                           properties_.GetAddress(), incoming.GetSourceAddress()));
+      model::packets::ReadRemoteExtendedFeaturesResponseBuilder::Create(
+          packet.GetDestinationAddress(), packet.GetSourceAddress(), error_code,
+          page_number, properties_.GetExtendedFeaturesMaximumPageNumber(),
+          properties_.GetExtendedFeatures(view.GetPageNumber())));
 }
 
-void LinkLayerController::IncomingDisconnectPacket(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "Disconnect Packet");
-  DisconnectView disconnect = DisconnectView::GetDisconnect(incoming);
+void LinkLayerController::IncomingReadRemoteExtendedFeaturesResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view =
+      model::packets::ReadRemoteExtendedFeaturesResponseView::Create(packet);
+  ASSERT(view.IsValid());
+  Address source = packet.GetSourceAddress();
+  if (connections_.IsDeviceConnected(source)) {
+    uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+    send_event_(
+        bluetooth::hci::ReadRemoteExtendedFeaturesCompleteBuilder::Create(
+            static_cast<bluetooth::hci::ErrorCode>(view.GetStatus()), handle,
+            view.GetPageNumber(), view.GetMaxPageNumber(), view.GetFeatures()));
+  } else {
+    LOG_INFO("Discarding response from a disconnected device %s",
+             source.ToString().c_str());
+  }
+}
+
+void LinkLayerController::IncomingReadRemoteVersion(
+    model::packets::LinkLayerPacketView packet) {
+  SendLinkLayerPacket(
+      model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create(
+          packet.GetDestinationAddress(), packet.GetSourceAddress(),
+          properties_.GetSupportedFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteVersionResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view =
+      model::packets::ReadRemoteVersionInformationResponseView::Create(packet);
+  ASSERT(view.IsValid());
+  Address source = packet.GetSourceAddress();
+  if (connections_.IsDeviceConnected(source)) {
+    uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+    send_event_(
+        bluetooth::hci::ReadRemoteVersionInformationCompleteBuilder::Create(
+            bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetLmpVersion(),
+            view.GetManufacturerName(), view.GetLmpSubversion()));
+  } else {
+    LOG_INFO("Discarding response from a disconnected device %s",
+             source.ToString().c_str());
+  }
+}
+
+void LinkLayerController::IncomingReadClockOffset(
+    model::packets::LinkLayerPacketView packet) {
+  SendLinkLayerPacket(model::packets::ReadClockOffsetResponseBuilder::Create(
+      packet.GetDestinationAddress(), packet.GetSourceAddress(),
+      properties_.GetClockOffset()));
+}
+
+void LinkLayerController::IncomingReadClockOffsetResponse(
+    model::packets::LinkLayerPacketView packet) {
+  auto view = model::packets::ReadClockOffsetResponseView::Create(packet);
+  ASSERT(view.IsValid());
+  Address source = packet.GetSourceAddress();
+  if (connections_.IsDeviceConnected(source)) {
+    uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+    send_event_(bluetooth::hci::ReadClockOffsetCompleteBuilder::Create(
+        bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetOffset()));
+  } else {
+    LOG_INFO("Discarding response from a disconnected device %s",
+             source.ToString().c_str());
+  }
+}
+
+void LinkLayerController::IncomingDisconnectPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("Disconnect Packet");
+  auto disconnect = model::packets::DisconnectView::Create(incoming);
+  ASSERT(disconnect.IsValid());
+
   Address peer = incoming.GetSourceAddress();
-  uint16_t handle = classic_connections_.GetHandle(peer);
+  uint16_t handle = connections_.GetHandle(peer);
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+    LOG_INFO("%s: Unknown connection @%s", __func__, peer.ToString().c_str());
     return;
   }
-  CHECK(classic_connections_.Disconnect(handle)) << "GetHandle() returned invalid handle " << handle;
+  ASSERT_LOG(connections_.Disconnect(handle), "GetHandle() returned invalid handle %hx", handle);
 
   uint8_t reason = disconnect.GetReason();
-  schedule_task_(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); });
+  ScheduleTask(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); });
 }
 
-void LinkLayerController::IncomingEncryptConnection(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingEncryptConnection(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("%s", __func__);
+
   // TODO: Check keys
   Address peer = incoming.GetSourceAddress();
-  uint16_t handle = classic_connections_.GetHandle(peer);
+  uint16_t handle = connections_.GetHandle(peer);
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+    LOG_INFO("%s: Unknown connection @%s", __func__, peer.ToString().c_str());
     return;
   }
-  send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
-  SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
-      EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+  send_event_(bluetooth::hci::EncryptionChangeBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle,
+      bluetooth::hci::EncryptionEnabled::ON));
+
+  uint16_t count = security_manager_.ReadKey(peer);
+  if (count == 0) {
+    LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str());
+    return;
+  }
+  auto array = security_manager_.GetKey(peer);
+  std::vector<uint8_t> key_vec{array.begin(), array.end()};
+  auto response = model::packets::EncryptConnectionResponseBuilder::Create(
+      properties_.GetAddress(), peer, key_vec);
+  SendLinkLayerPacket(std::move(response));
 }
 
-void LinkLayerController::IncomingEncryptConnectionResponse(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingEncryptConnectionResponse(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("%s", __func__);
   // TODO: Check keys
-  uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+  uint16_t handle = connections_.GetHandle(incoming.GetSourceAddress());
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, incoming.GetSourceAddress().ToString().c_str());
+    LOG_INFO("%s: Unknown connection @%s", __func__, incoming.GetSourceAddress().ToString().c_str());
     return;
   }
-  send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
+  auto packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle,
+      bluetooth::hci::EncryptionEnabled::ON);
+  send_event_(std::move(packet));
 }
 
-void LinkLayerController::IncomingInquiryPacket(LinkLayerPacketView incoming) {
-  InquiryView inquiry = InquiryView::GetInquiry(incoming);
-  std::unique_ptr<InquiryResponseBuilder> inquiry_response;
-  switch (inquiry.GetType()) {
-    case (Inquiry::InquiryType::STANDARD):
-      inquiry_response = InquiryResponseBuilder::CreateStandard(
-          properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset());
-      break;
+void LinkLayerController::IncomingInquiryPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto inquiry = model::packets::InquiryView::Create(incoming);
+  ASSERT(inquiry.IsValid());
 
-    case (Inquiry::InquiryType::RSSI):
-      inquiry_response =
-          InquiryResponseBuilder::CreateRssi(properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(),
-                                             properties_.GetClockOffset(), GetRssi());
-      break;
+  Address peer = incoming.GetSourceAddress();
 
-    case (Inquiry::InquiryType::EXTENDED):
-      inquiry_response = InquiryResponseBuilder::CreateExtended(
-          properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset(),
-          GetRssi(), properties_.GetExtendedInquiryData());
-      break;
+  switch (inquiry.GetInquiryType()) {
+    case (model::packets::InquiryType::STANDARD): {
+      auto inquiry_response = model::packets::InquiryResponseBuilder::Create(
+          properties_.GetAddress(), peer,
+          properties_.GetPageScanRepetitionMode(),
+          properties_.GetClassOfDevice(), properties_.GetClockOffset());
+      SendLinkLayerPacket(std::move(inquiry_response));
+    } break;
+    case (model::packets::InquiryType::RSSI): {
+      auto inquiry_response =
+          model::packets::InquiryResponseWithRssiBuilder::Create(
+              properties_.GetAddress(), peer,
+              properties_.GetPageScanRepetitionMode(),
+              properties_.GetClassOfDevice(), properties_.GetClockOffset(),
+              GetRssi());
+      SendLinkLayerPacket(std::move(inquiry_response));
+    } break;
+    case (model::packets::InquiryType::EXTENDED): {
+      auto inquiry_response =
+          model::packets::ExtendedInquiryResponseBuilder::Create(
+              properties_.GetAddress(), peer,
+              properties_.GetPageScanRepetitionMode(),
+              properties_.GetClassOfDevice(), properties_.GetClockOffset(),
+              GetRssi(), properties_.GetExtendedInquiryData());
+      SendLinkLayerPacket(std::move(inquiry_response));
+
+    } break;
     default:
-      LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType()));
+      LOG_WARN("Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType()));
       return;
   }
-  SendLinkLayerPacket(LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response), properties_.GetAddress(),
-                                                                  incoming.GetSourceAddress()));
-  // TODO: Send an Inquriy Response Notification Event 7.7.74
+  // TODO: Send an Inquiry Response Notification Event 7.7.74
 }
 
-void LinkLayerController::IncomingInquiryResponsePacket(LinkLayerPacketView incoming) {
-  InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(incoming);
+void LinkLayerController::IncomingInquiryResponsePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto basic_inquiry_response =
+      model::packets::BasicInquiryResponseView::Create(incoming);
+  ASSERT(basic_inquiry_response.IsValid());
   std::vector<uint8_t> eir;
 
-  switch (inquiry_response.GetType()) {
-    case (Inquiry::InquiryType::STANDARD): {
-      LOG_WARN(LOG_TAG, "Incoming Standard Inquiry Response");
+  switch (basic_inquiry_response.GetInquiryType()) {
+    case (model::packets::InquiryType::STANDARD): {
       // TODO: Support multiple inquiries in the same packet.
-      std::unique_ptr<EventPacketBuilder> inquiry_result = EventPacketBuilder::CreateInquiryResultEvent();
-      bool result_added =
-          inquiry_result->AddInquiryResult(incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
-                                           inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset());
-      CHECK(result_added);
-      send_event_(inquiry_result->ToVector());
+      auto inquiry_response =
+          model::packets::InquiryResponseView::Create(basic_inquiry_response);
+      ASSERT(inquiry_response.IsValid());
+
+      auto page_scan_repetition_mode =
+          (bluetooth::hci::PageScanRepetitionMode)
+              inquiry_response.GetPageScanRepetitionMode();
+
+      auto packet = bluetooth::hci::InquiryResultBuilder::Create(
+          0x01, inquiry_response.GetSourceAddress(), page_scan_repetition_mode,
+          inquiry_response.GetClassOfDevice(),
+          inquiry_response.GetClockOffset());
+
+      send_event_(std::move(packet));
     } break;
 
-    case (Inquiry::InquiryType::RSSI):
-      LOG_WARN(LOG_TAG, "Incoming RSSI Inquiry Response");
-      send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
-                      incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
-                      inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
-                      ->ToVector());
-      break;
+    case (model::packets::InquiryType::RSSI): {
+      auto inquiry_response =
+          model::packets::InquiryResponseWithRssiView::Create(
+              basic_inquiry_response);
+      ASSERT(inquiry_response.IsValid());
 
-    case (Inquiry::InquiryType::EXTENDED): {
-      LOG_WARN(LOG_TAG, "Incoming Extended Inquiry Response");
-      auto eir_itr = inquiry_response.GetExtendedData();
-      size_t eir_bytes = eir_itr.NumBytesRemaining();
-      LOG_WARN(LOG_TAG, "Payload size = %d", static_cast<int>(eir_bytes));
-      for (size_t i = 0; i < eir_bytes; i++) {
-        eir.push_back(eir_itr.extract<uint8_t>());
+      auto page_scan_repetition_mode =
+          (bluetooth::hci::PageScanRepetitionMode)
+              inquiry_response.GetPageScanRepetitionMode();
+
+      auto packet = bluetooth::hci::InquiryResultWithRssiBuilder::Create(
+          0x01, inquiry_response.GetSourceAddress(), page_scan_repetition_mode,
+          inquiry_response.GetClassOfDevice(),
+          inquiry_response.GetClockOffset(), inquiry_response.GetRssi());
+      send_event_(std::move(packet));
+    } break;
+
+    case (model::packets::InquiryType::EXTENDED): {
+      auto inquiry_response =
+          model::packets::ExtendedInquiryResponseView::Create(
+              basic_inquiry_response);
+      ASSERT(inquiry_response.IsValid());
+
+      std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+          std::make_unique<bluetooth::packet::RawBuilder>();
+      raw_builder_ptr->AddOctets1(kNumCommandPackets);
+      raw_builder_ptr->AddAddress(inquiry_response.GetSourceAddress());
+      raw_builder_ptr->AddOctets1(inquiry_response.GetPageScanRepetitionMode());
+      raw_builder_ptr->AddOctets1(0x00);  // _reserved_
+      auto class_of_device = inquiry_response.GetClassOfDevice();
+      for (unsigned int i = 0; i < class_of_device.kLength; i++) {
+        raw_builder_ptr->AddOctets1(class_of_device.cod[i]);
       }
-      send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
-                      incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
-                      inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
-                      ->ToVector());
+      raw_builder_ptr->AddOctets2(inquiry_response.GetClockOffset());
+      raw_builder_ptr->AddOctets1(inquiry_response.GetRssi());
+      raw_builder_ptr->AddOctets(inquiry_response.GetExtendedData());
+
+      auto packet = bluetooth::hci::EventPacketBuilder::Create(
+          bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT,
+          std::move(raw_builder_ptr));
+      send_event_(std::move(packet));
     } break;
     default:
-      LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry Response of type %d", static_cast<int>(inquiry_response.GetType()));
+      LOG_WARN("Unhandled Incoming Inquiry Response of type %d",
+               static_cast<int>(basic_inquiry_response.GetInquiryType()));
   }
 }
 
-void LinkLayerController::IncomingIoCapabilityRequestPacket(LinkLayerPacketView incoming) {
-  LOG_DEBUG(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingIoCapabilityRequestPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_DEBUG("%s", __func__);
   if (!simple_pairing_mode_enabled_) {
-    LOG_WARN(LOG_TAG, "%s: Only simple pairing mode is implemented", __func__);
+    LOG_WARN("%s: Only simple pairing mode is implemented", __func__);
     return;
   }
-  auto request = IoCapabilityView::GetIoCapability(incoming);
-  Address peer = incoming.GetSourceAddress();
 
+  auto request = model::packets::IoCapabilityRequestView::Create(incoming);
+  ASSERT(request.IsValid());
+
+  Address peer = incoming.GetSourceAddress();
   uint8_t io_capability = request.GetIoCapability();
   uint8_t oob_data_present = request.GetOobDataPresent();
   uint8_t authentication_requirements = request.GetAuthenticationRequirements();
 
-  uint16_t handle = classic_connections_.GetHandle(peer);
+  uint16_t handle = connections_.GetHandle(peer);
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, peer.ToString().c_str());
+    LOG_INFO("%s: Device not connected %s", __func__, peer.ToString().c_str());
     return;
   }
 
@@ -411,260 +655,318 @@
 
   security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
 
-  send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
-                                                                  authentication_requirements)
-                  ->ToVector());
+  auto packet = bluetooth::hci::IoCapabilityResponseBuilder::Create(
+      peer, static_cast<bluetooth::hci::IoCapability>(io_capability),
+      static_cast<bluetooth::hci::OobDataPresent>(oob_data_present),
+      static_cast<bluetooth::hci::AuthenticationRequirements>(
+          authentication_requirements));
+  send_event_(std::move(packet));
 
   StartSimplePairing(peer);
 }
 
-void LinkLayerController::IncomingIoCapabilityResponsePacket(LinkLayerPacketView incoming) {
-  LOG_DEBUG(LOG_TAG, "%s", __func__);
-  auto response = IoCapabilityView::GetIoCapability(incoming);
+void LinkLayerController::IncomingIoCapabilityResponsePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_DEBUG("%s", __func__);
+
+  auto response = model::packets::IoCapabilityResponseView::Create(incoming);
+  ASSERT(response.IsValid());
+
   Address peer = incoming.GetSourceAddress();
   uint8_t io_capability = response.GetIoCapability();
   uint8_t oob_data_present = response.GetOobDataPresent();
   uint8_t authentication_requirements = response.GetAuthenticationRequirements();
 
-  security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
+  security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present,
+                                        authentication_requirements);
 
-  send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
-                                                                  authentication_requirements)
-                  ->ToVector());
+  auto packet = bluetooth::hci::IoCapabilityResponseBuilder::Create(
+      peer, static_cast<bluetooth::hci::IoCapability>(io_capability),
+      static_cast<bluetooth::hci::OobDataPresent>(oob_data_present),
+      static_cast<bluetooth::hci::AuthenticationRequirements>(
+          authentication_requirements));
+  send_event_(std::move(packet));
 
   PairingType pairing_type = security_manager_.GetSimplePairingType();
   if (pairing_type != PairingType::INVALID) {
-    schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
+    ScheduleTask(milliseconds(5), [this, peer, pairing_type]() {
+      AuthenticateRemoteStage1(peer, pairing_type);
+    });
   } else {
-    LOG_INFO(LOG_TAG, "%s: Security Manager returned INVALID", __func__);
+    LOG_INFO("%s: Security Manager returned INVALID", __func__);
   }
 }
 
-void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(LinkLayerPacketView incoming) {
-  LOG_DEBUG(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_DEBUG("%s", __func__);
   Address peer = incoming.GetSourceAddress();
 
-  CHECK(security_manager_.GetAuthenticationAddress() == peer);
+  ASSERT(security_manager_.GetAuthenticationAddress() == peer);
 
   security_manager_.InvalidateIoCapabilities();
 }
 
-void LinkLayerController::IncomingLeAdvertisementPacket(LinkLayerPacketView incoming) {
+void LinkLayerController::IncomingLeAdvertisementPacket(
+    model::packets::LinkLayerPacketView incoming) {
   // TODO: Handle multiple advertisements per packet.
 
-  LeAdvertisementView advertisement = LeAdvertisementView::GetLeAdvertisementView(incoming);
-  LeAdvertisement::AdvertisementType adv_type = advertisement.GetAdvertisementType();
-  LeAdvertisement::AddressType addr_type = advertisement.GetAddressType();
+  Address address = incoming.GetSourceAddress();
+  auto advertisement = model::packets::LeAdvertisementView::Create(incoming);
+  ASSERT(advertisement.IsValid());
+  auto adv_type = static_cast<LeAdvertisement::AdvertisementType>(
+      advertisement.GetAdvertisementType());
+  auto address_type =
+      static_cast<LeAdvertisement::AddressType>(advertisement.GetAddressType());
 
   if (le_scan_enable_) {
-    vector<uint8_t> ad;
-    auto itr = advertisement.GetData();
-    size_t ad_size = itr.NumBytesRemaining();
-    for (size_t i = 0; i < ad_size; i++) {
-      ad.push_back(itr.extract<uint8_t>());
-    }
-    std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+    vector<uint8_t> ad = advertisement.GetData();
 
-    if (!le_adverts->AddLeAdvertisingReport(adv_type, addr_type, incoming.GetSourceAddress(), ad, GetRssi())) {
-      LOG_INFO(LOG_TAG, "Couldn't add the advertising report.");
-    } else {
-      send_event_(le_adverts->ToVector());
-    }
+    std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+        std::make_unique<bluetooth::packet::RawBuilder>();
+    raw_builder_ptr->AddOctets1(
+        static_cast<uint8_t>(bluetooth::hci::SubeventCode::ADVERTISING_REPORT));
+    raw_builder_ptr->AddOctets1(0x01);  // num reports
+    raw_builder_ptr->AddOctets1(static_cast<uint8_t>(adv_type));
+    raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type));
+    raw_builder_ptr->AddAddress(address);
+    raw_builder_ptr->AddOctets1(ad.size());
+    raw_builder_ptr->AddOctets(ad);
+    raw_builder_ptr->AddOctets1(GetRssi());
+    auto packet = bluetooth::hci::EventPacketBuilder::Create(
+        bluetooth::hci::EventCode::LE_META_EVENT, std::move(raw_builder_ptr));
+    send_event_(std::move(packet));
   }
 
-#if 0
-      // Connect
-      if (le_connect_ && (adv_type == BTM_BLE_CONNECT_EVT ||
-                          adv_type == BTM_BLE_CONNECT_DIR_EVT)) {
-        LOG_INFO(LOG_TAG, "Connecting to device %d", static_cast<int>(dev));
-        if (le_peer_address_ == addr && le_peer_address_type_ == addr_type &&
-            remote_devices_[dev]->LeConnect()) {
-          uint16_t handle = LeGetHandle();
-          send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
-              hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
-              2, 3)->ToVector());
-
-          // TODO: LeGetConnInterval(), LeGetConnLatency(),
-          // LeGetSupervisionTimeout()));
-          le_connect_ = false;
-
-          std::shared_ptr<Connection> new_connection =
-              std::make_shared<Connection>(remote_devices_[dev], handle);
-          /*
-          connections_.push_back(new_connection);
-
-          remote_devices_[dev]->SetConnection(new_connection);
-          */
-        }
-
-        if (LeWhiteListContainsDevice(addr, addr_type) &&
-            remote_devices_[dev]->LeConnect()) {
-          LOG_INFO(LOG_TAG, "White List Connecting to device %d",
-                   static_cast<int>(dev));
-          uint16_t handle = LeGetHandle();
-          send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
-              hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
-              2, 3)->ToVector());
-          // TODO: LeGetConnInterval(), LeGetConnLatency(),
-          // LeGetSupervisionTimeout()));
-          le_connect_ = false;
-
-          std::shared_ptr<Connection> new_connection =
-              std::make_shared<Connection>(remote_devices_[dev], handle);
-          /*
-          connections_.push_back(new_connection);
-          remote_devices_[dev]->SetConnection(new_connection);
-          */
-        }
-      }
-#endif
-
   // Active scanning
   if (le_scan_enable_ && le_scan_type_ == 1) {
-    std::shared_ptr<LinkLayerPacketBuilder> to_send =
-        LinkLayerPacketBuilder::WrapLeScan(properties_.GetLeAddress(), incoming.GetSourceAddress());
-    SendLELinkLayerPacket(to_send);
+    auto to_send = model::packets::LeScanBuilder::Create(
+        properties_.GetLeAddress(), address);
+    SendLeLinkLayerPacket(std::move(to_send));
+  }
+
+  // Connect
+  if ((le_connect_ && le_peer_address_ == address && le_peer_address_type_ == static_cast<uint8_t>(address_type) &&
+       (adv_type == LeAdvertisement::AdvertisementType::ADV_IND ||
+        adv_type == LeAdvertisement::AdvertisementType::ADV_DIRECT_IND)) ||
+      (LeWhiteListContainsDevice(address, static_cast<uint8_t>(address_type)))) {
+    if (!connections_.CreatePendingLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(address_type))) {
+      LOG_WARN("%s: CreatePendingLeConnection failed for connection to %s (type %hhx)", __func__,
+               incoming.GetSourceAddress().ToString().c_str(), address_type);
+    }
+    LOG_INFO("%s: connecting to %s (type %hhx)", __func__, incoming.GetSourceAddress().ToString().c_str(),
+             address_type);
+    le_connect_ = false;
+    le_scan_enable_ = false;
+
+    auto to_send = model::packets::LeConnectBuilder::Create(
+        properties_.GetLeAddress(), incoming.GetSourceAddress(),
+        le_connection_interval_min_, le_connection_interval_max_,
+        le_connection_latency_, le_connection_supervision_timeout_,
+        static_cast<uint8_t>(le_address_type_));
+
+    SendLeLinkLayerPacket(std::move(to_send));
   }
 }
 
-void LinkLayerController::IncomingLeScanPacket(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "LE Scan Packet");
-  std::unique_ptr<LeAdvertisementBuilder> response = LeAdvertisementBuilder::Create(
-      static_cast<LeAdvertisement::AddressType>(properties_.GetLeAddressType()),
-      static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
-      properties_.GetLeScanResponse());
-  std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeScanResponse(
-      std::move(response), properties_.GetLeAddress(), incoming.GetSourceAddress());
-  SendLELinkLayerPacket(to_send);
-}
-
-void LinkLayerController::IncomingLeScanResponsePacket(LinkLayerPacketView incoming) {
-  LeAdvertisementView scan_response = LeAdvertisementView::GetLeAdvertisementView(incoming);
-  vector<uint8_t> ad;
-  auto itr = scan_response.GetData();
-  size_t scan_size = itr.NumBytesRemaining();
-  for (size_t i = 0; i < scan_size; i++) {
-    ad.push_back(itr.extract<uint8_t>());
-  }
-
-  std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
-
-  if (!le_adverts->AddLeAdvertisingReport(scan_response.GetAdvertisementType(), scan_response.GetAddressType(),
-                                          incoming.GetSourceAddress(), ad, GetRssi())) {
-    LOG_INFO(LOG_TAG, "Couldn't add the scan response.");
-  } else {
-    LOG_INFO(LOG_TAG, "Sending scan response");
-    send_event_(le_adverts->ToVector());
-  }
-}
-
-void LinkLayerController::IncomingPagePacket(LinkLayerPacketView incoming) {
-  PageView page = PageView::GetPage(incoming);
-  LOG_INFO(LOG_TAG, "%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str());
-
-  if (!classic_connections_.CreatePendingConnection(incoming.GetSourceAddress())) {
-    // Send a response to indicate that we're busy, or drop the packet?
-    LOG_WARN(LOG_TAG, "%s: Failed to create a pending connection", __func__);
-  }
-
-  send_event_(EventPacketBuilder::CreateConnectionRequestEvent(incoming.GetSourceAddress(), page.GetClassOfDevice(),
-                                                               hci::LinkType::ACL)
-                  ->ToVector());
-}
-
-void LinkLayerController::IncomingPageRejectPacket(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
-  PageRejectView reject = PageRejectView::GetPageReject(incoming);
-  LOG_INFO(LOG_TAG, "%s: Sending CreateConnectionComplete", __func__);
-  send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reject.GetReason()), 0x0eff,
-                                                                incoming.GetSourceAddress(), hci::LinkType::ACL, false)
-                  ->ToVector());
-}
-
-void LinkLayerController::IncomingPageResponsePacket(LinkLayerPacketView incoming) {
-  LOG_INFO(LOG_TAG, "%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
-  uint16_t handle = classic_connections_.CreateConnection(incoming.GetSourceAddress());
+void LinkLayerController::HandleLeConnection(Address address, uint8_t address_type, uint8_t own_address_type,
+                                             uint8_t role, uint16_t connection_interval, uint16_t connection_latency,
+                                             uint16_t supervision_timeout) {
+  // TODO: Choose between LeConnectionComplete and LeEnhancedConnectionComplete
+  uint16_t handle = connections_.CreateLeConnection(address, address_type, own_address_type);
   if (handle == acl::kReservedHandle) {
-    LOG_WARN(LOG_TAG, "%s: No free handles", __func__);
+    LOG_WARN("%s: No pending connection for connection from %s (type %hhx)", __func__, address.ToString().c_str(),
+             address_type);
     return;
   }
-  LOG_INFO(LOG_TAG, "%s: Sending CreateConnectionComplete", __func__);
-  send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle,
-                                                                incoming.GetSourceAddress(), hci::LinkType::ACL, false)
-                  ->ToVector());
+  auto packet = bluetooth::hci::LeConnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle,
+      static_cast<bluetooth::hci::Role>(role),
+      static_cast<bluetooth::hci::AddressType>(address_type), address,
+      connection_interval, connection_latency, supervision_timeout,
+      static_cast<bluetooth::hci::MasterClockAccuracy>(0x00));
+  send_event_(std::move(packet));
 }
 
-void LinkLayerController::IncomingResponsePacket(LinkLayerPacketView incoming) {
-  ResponseView response = ResponseView::GetResponse(incoming);
+void LinkLayerController::IncomingLeConnectPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto connect = model::packets::LeConnectView::Create(incoming);
+  ASSERT(connect.IsValid());
+  uint16_t connection_interval = (connect.GetLeConnectionIntervalMax() + connect.GetLeConnectionIntervalMin()) / 2;
+  if (!connections_.CreatePendingLeConnection(incoming.GetSourceAddress(),
+                                              static_cast<uint8_t>(connect.GetAddressType()))) {
+    LOG_WARN("%s: CreatePendingLeConnection failed for connection from %s (type %hhx)", __func__,
+             incoming.GetSourceAddress().ToString().c_str(), connect.GetAddressType());
+    return;
+  }
+  HandleLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(connect.GetAddressType()),
+                     static_cast<uint8_t>(properties_.GetLeAdvertisingOwnAddressType()),
+                     static_cast<uint8_t>(hci::Role::SLAVE), connection_interval, connect.GetLeConnectionLatency(),
+                     connect.GetLeConnectionSupervisionTimeout());
 
-  // TODO: Check to see if I'm expecting this response.
+  auto to_send = model::packets::LeConnectCompleteBuilder::Create(
+      incoming.GetDestinationAddress(), incoming.GetSourceAddress(),
+      connection_interval, connect.GetLeConnectionLatency(),
+      connect.GetLeConnectionSupervisionTimeout(),
+      properties_.GetLeAdvertisingOwnAddressType());
+  SendLeLinkLayerPacket(std::move(to_send));
+}
 
-  hci::OpCode opcode = static_cast<hci::OpCode>(response.GetOpcode());
-  auto args = response.GetResponseData();
-  hci::Status status = static_cast<hci::Status>(args.extract<uint64_t>());
+void LinkLayerController::IncomingLeConnectCompletePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto complete = model::packets::LeConnectCompleteView::Create(incoming);
+  ASSERT(complete.IsValid());
+  HandleLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(complete.GetAddressType()),
+                     static_cast<uint8_t>(le_address_type_), static_cast<uint8_t>(hci::Role::MASTER),
+                     complete.GetLeConnectionInterval(), complete.GetLeConnectionLatency(),
+                     complete.GetLeConnectionSupervisionTimeout());
+}
 
-  uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+void LinkLayerController::IncomingLeScanPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("LE Scan Packet");
 
-  switch (opcode) {
-    case (hci::OpCode::REMOTE_NAME_REQUEST): {
-      std::string remote_name = "";
-      size_t length = args.extract<uint64_t>();
-      uint64_t word = 0;
-      for (size_t b = 0; b < length; b++) {
-        size_t byte = b % 8;
-        if (byte == 0) {
-          word = args.extract<uint64_t>();
-        }
-        remote_name += static_cast<uint8_t>(word >> (byte * 8));
-      }
-      send_event_(
-          EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(status, incoming.GetSourceAddress(), remote_name)
-              ->ToVector());
-    } break;
-    case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES): {
-      send_event_(
-          EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(status, handle, args.extract<uint64_t>())->ToVector());
-    } break;
-    case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
-      if (status == hci::Status::SUCCESS) {
-        send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
-                        status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
-                        ->ToVector());
-      } else {
-        send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(status, handle, 0, 0, 0)->ToVector());
-      }
-    } break;
-    case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION): {
-      send_event_(EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
-                      status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
-                      ->ToVector());
-      LOG_INFO(LOG_TAG, "Read remote version handle 0x%04x", handle);
-    } break;
-    case (hci::OpCode::READ_CLOCK_OFFSET): {
-      send_event_(EventPacketBuilder::CreateReadClockOffsetEvent(status, handle, args.extract<uint64_t>())->ToVector());
-    } break;
-    default:
-      LOG_INFO(LOG_TAG, "Unhandled response to command 0x%04x", static_cast<uint16_t>(opcode));
+  auto to_send = model::packets::LeScanResponseBuilder::Create(
+      properties_.GetLeAddress(), incoming.GetSourceAddress(),
+      static_cast<model::packets::AddressType>(properties_.GetLeAddressType()),
+      static_cast<model::packets::AdvertisementType>(
+          properties_.GetLeAdvertisementType()),
+      properties_.GetLeScanResponse());
+
+  SendLeLinkLayerPacket(std::move(to_send));
+}
+
+void LinkLayerController::IncomingLeScanResponsePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto scan_response = model::packets::LeScanResponseView::Create(incoming);
+  ASSERT(scan_response.IsValid());
+  vector<uint8_t> ad = scan_response.GetData();
+  auto adv_type = static_cast<LeAdvertisement::AdvertisementType>(
+      scan_response.GetAdvertisementType());
+  auto address_type =
+      static_cast<LeAdvertisement::AddressType>(scan_response.GetAddressType());
+
+  std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+      std::make_unique<bluetooth::packet::RawBuilder>();
+  raw_builder_ptr->AddOctets1(
+      static_cast<uint8_t>(bluetooth::hci::SubeventCode::ADVERTISING_REPORT));
+  raw_builder_ptr->AddOctets1(0x01);  // num reports
+  raw_builder_ptr->AddOctets1(static_cast<uint8_t>(adv_type));
+  raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type));
+  raw_builder_ptr->AddAddress(incoming.GetSourceAddress());
+  raw_builder_ptr->AddOctets1(ad.size());
+  raw_builder_ptr->AddOctets(ad);
+  raw_builder_ptr->AddOctets1(GetRssi());
+  auto packet = bluetooth::hci::EventPacketBuilder::Create(
+      bluetooth::hci::EventCode::LE_META_EVENT, std::move(raw_builder_ptr));
+  send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPagePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  auto page = model::packets::PageView::Create(incoming);
+  ASSERT(page.IsValid());
+  LOG_INFO("%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+
+  if (!connections_.CreatePendingConnection(
+          incoming.GetSourceAddress(), properties_.GetAuthenticationEnable())) {
+    // Send a response to indicate that we're busy, or drop the packet?
+    LOG_WARN("%s: Failed to create a pending connection for %s", __func__,
+             incoming.GetSourceAddress().ToString().c_str());
+  }
+
+  bluetooth::hci::Address source_address;
+  bluetooth::hci::Address::FromString(page.GetSourceAddress().ToString(),
+                                      source_address);
+
+  auto packet = bluetooth::hci::ConnectionRequestBuilder::Create(
+      source_address, page.GetClassOfDevice(),
+      bluetooth::hci::ConnectionRequestLinkType::ACL);
+
+  send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPageRejectPacket(
+    model::packets::LinkLayerPacketView incoming) {
+  LOG_INFO("%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+  auto reject = model::packets::PageRejectView::Create(incoming);
+  ASSERT(reject.IsValid());
+  LOG_INFO("%s: Sending CreateConnectionComplete", __func__);
+  auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      static_cast<bluetooth::hci::ErrorCode>(reject.GetReason()), 0x0eff,
+      incoming.GetSourceAddress(), bluetooth::hci::LinkType::ACL,
+      bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPageResponsePacket(
+    model::packets::LinkLayerPacketView incoming) {
+  Address peer = incoming.GetSourceAddress();
+  LOG_INFO("%s: %s", __func__, peer.ToString().c_str());
+  bool awaiting_authentication = connections_.AuthenticatePendingConnection();
+  uint16_t handle = connections_.CreateConnection(peer);
+  if (handle == acl::kReservedHandle) {
+    LOG_WARN("%s: No free handles", __func__);
+    return;
+  }
+  auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle, incoming.GetSourceAddress(),
+      bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet));
+
+  if (awaiting_authentication) {
+    ScheduleTask(milliseconds(5), [this, peer, handle]() {
+      HandleAuthenticationRequest(peer, handle);
+    });
   }
 }
 
 void LinkLayerController::TimerTick() {
   if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) Inquiry();
   if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) PageScan();
+  LeAdvertising();
   Connections();
 }
 
+void LinkLayerController::LeAdvertising() {
+  if (!le_advertising_enable_) {
+    return;
+  }
+  steady_clock::time_point now = steady_clock::now();
+  if (duration_cast<milliseconds>(now - last_le_advertisement_) < milliseconds(200)) {
+    return;
+  }
+  last_le_advertisement_ = now;
+
+  auto own_address_type = static_cast<model::packets::AddressType>(
+      properties_.GetLeAdvertisingOwnAddressType());
+  Address advertising_address = Address::kEmpty;
+  if (own_address_type == model::packets::AddressType::PUBLIC) {
+    advertising_address = properties_.GetAddress();
+  } else if (own_address_type == model::packets::AddressType::RANDOM) {
+    advertising_address = properties_.GetLeAddress();
+  }
+  ASSERT(advertising_address != Address::kEmpty);
+  auto to_send = model::packets::LeAdvertisementBuilder::Create(
+      advertising_address, Address::kEmpty, own_address_type,
+      static_cast<model::packets::AdvertisementType>(own_address_type),
+      properties_.GetLeAdvertisement());
+  SendLeLinkLayerPacket(std::move(to_send));
+}
+
 void LinkLayerController::Connections() {
   // TODO: Keep connections alive?
 }
 
 void LinkLayerController::RegisterEventChannel(
-    const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+    const std::function<
+        void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>& callback) {
   send_event_ = callback;
 }
 
 void LinkLayerController::RegisterAclChannel(
-    const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+    const std::function<
+        void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>& callback) {
   send_acl_ = callback;
 }
 
@@ -673,8 +975,16 @@
   send_sco_ = callback;
 }
 
+void LinkLayerController::RegisterIsoChannel(
+    const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+        callback) {
+  send_iso_ = callback;
+}
+
 void LinkLayerController::RegisterRemoteChannel(
-    const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>, Phy::Type)>& callback) {
+    const std::function<void(
+        std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>&
+        callback) {
   send_to_remote_ = callback;
 }
 
@@ -683,27 +993,43 @@
   schedule_task_ = event_scheduler;
 }
 
+AsyncTaskId LinkLayerController::ScheduleTask(milliseconds delay_ms, const TaskCallback& callback) {
+  if (schedule_task_) {
+    return schedule_task_(delay_ms, callback);
+  } else {
+    callback();
+    return 0;
+  }
+}
+
 void LinkLayerController::RegisterPeriodicTaskScheduler(
     std::function<AsyncTaskId(milliseconds, milliseconds, const TaskCallback&)> periodic_event_scheduler) {
   schedule_periodic_task_ = periodic_event_scheduler;
 }
 
+void LinkLayerController::CancelScheduledTask(AsyncTaskId task_id) {
+  if (schedule_task_ && cancel_task_) {
+    cancel_task_(task_id);
+  }
+}
+
 void LinkLayerController::RegisterTaskCancel(std::function<void(AsyncTaskId)> task_cancel) {
   cancel_task_ = task_cancel;
 }
 
 void LinkLayerController::AddControllerEvent(milliseconds delay, const TaskCallback& task) {
-  controller_events_.push_back(schedule_task_(delay, task));
+  controller_events_.push_back(ScheduleTask(delay, task));
 }
 
 void LinkLayerController::WriteSimplePairingMode(bool enabled) {
-  CHECK(enabled) << "The spec says don't disable this!";
+  ASSERT_LOG(enabled, "The spec says don't disable this!");
   simple_pairing_mode_enabled_ = enabled;
 }
 
 void LinkLayerController::StartSimplePairing(const Address& address) {
   // IO Capability Exchange (See the Diagram in the Spec)
-  send_event_(EventPacketBuilder::CreateIoCapabilityRequestEvent(address)->ToVector());
+  auto packet = bluetooth::hci::IoCapabilityRequestBuilder::Create(address);
+  send_event_(std::move(packet));
 
   // Get a Key, then authenticate
   // PublicKeyExchange(address);
@@ -712,342 +1038,489 @@
 }
 
 void LinkLayerController::AuthenticateRemoteStage1(const Address& peer, PairingType pairing_type) {
-  CHECK(security_manager_.GetAuthenticationAddress() == peer);
+  ASSERT(security_manager_.GetAuthenticationAddress() == peer);
   // TODO: Public key exchange first?
   switch (pairing_type) {
     case PairingType::AUTO_CONFIRMATION:
-      send_event_(EventPacketBuilder::CreateUserConfirmationRequestEvent(peer, 123456)->ToVector());
+      send_event_(
+          bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
       break;
     case PairingType::CONFIRM_Y_N:
-      CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+      send_event_(
+          bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
       break;
     case PairingType::DISPLAY_PIN:
-      CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+      send_event_(
+          bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
       break;
     case PairingType::DISPLAY_AND_CONFIRM:
-      CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+      send_event_(
+          bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
       break;
     case PairingType::INPUT_PIN:
-      CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
-      break;
-    case PairingType::INVALID:
-      CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+      send_event_(bluetooth::hci::UserPasskeyRequestBuilder::Create(peer));
       break;
     default:
-      CHECK(false) << __func__ << ": Invalid PairingType " << static_cast<int>(pairing_type);
+      LOG_ALWAYS_FATAL("Invalid PairingType %d", static_cast<int>(pairing_type));
   }
 }
 
 void LinkLayerController::AuthenticateRemoteStage2(const Address& peer) {
   uint16_t handle = security_manager_.GetAuthenticationHandle();
-  CHECK(security_manager_.GetAuthenticationAddress() == peer);
+  ASSERT(security_manager_.GetAuthenticationAddress() == peer);
   // Check key in security_manager_ ?
-  send_event_(EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::SUCCESS, handle)->ToVector());
+  auto packet = bluetooth::hci::AuthenticationCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle);
+  send_event_(std::move(packet));
 }
 
-hci::Status LinkLayerController::LinkKeyRequestReply(const Address& peer, PacketView<true> key) {
-  std::vector<uint8_t> key_vec(key.begin(), key.end());
-  security_manager_.WriteKey(peer, key_vec);
+bluetooth::hci::ErrorCode LinkLayerController::LinkKeyRequestReply(
+    const Address& peer, const std::array<uint8_t, 16>& key) {
+  security_manager_.WriteKey(peer, key);
   security_manager_.AuthenticationRequestFinished();
 
-  schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
+  ScheduleTask(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::LinkKeyRequestNegativeReply(const Address& address) {
+bluetooth::hci::ErrorCode LinkLayerController::LinkKeyRequestNegativeReply(
+    const Address& address) {
   security_manager_.DeleteKey(address);
   // Simple pairing to get a key
-  uint16_t handle = classic_connections_.GetHandle(address);
+  uint16_t handle = connections_.GetHandle(address);
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, address.ToString().c_str());
-    return hci::Status::UNKNOWN_CONNECTION;
+    LOG_INFO("%s: Device not connected %s", __func__, address.ToString().c_str());
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
   security_manager_.AuthenticationRequest(address, handle);
 
-  schedule_task_(milliseconds(5), [this, address]() { StartSimplePairing(address); });
-  return hci::Status::SUCCESS;
+  ScheduleTask(milliseconds(5), [this, address]() { StartSimplePairing(address); });
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::IoCapabilityRequestReply(const Address& peer, uint8_t io_capability,
-                                                          uint8_t oob_data_present_flag,
-                                                          uint8_t authentication_requirements) {
+bluetooth::hci::ErrorCode LinkLayerController::IoCapabilityRequestReply(
+    const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
+    uint8_t authentication_requirements) {
   security_manager_.SetLocalIoCapability(peer, io_capability, oob_data_present_flag, authentication_requirements);
 
   PairingType pairing_type = security_manager_.GetSimplePairingType();
+
   if (pairing_type != PairingType::INVALID) {
-    schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
-    SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityResponse(
-        IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
-        properties_.GetAddress(), peer));
+    ScheduleTask(milliseconds(5), [this, peer, pairing_type]() {
+      AuthenticateRemoteStage1(peer, pairing_type);
+    });
+    SendLinkLayerPacket(model::packets::IoCapabilityResponseBuilder::Create(
+        properties_.GetAddress(), peer, io_capability, oob_data_present_flag,
+        authentication_requirements));
   } else {
-    LOG_INFO(LOG_TAG, "%s: Requesting remote capability", __func__);
-    SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityRequest(
-        IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
-        properties_.GetAddress(), peer));
+    LOG_INFO("%s: Requesting remote capability", __func__);
+
+    SendLinkLayerPacket(model::packets::IoCapabilityRequestBuilder::Create(
+        properties_.GetAddress(), peer, io_capability, oob_data_present_flag,
+        authentication_requirements));
   }
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason) {
+bluetooth::hci::ErrorCode LinkLayerController::IoCapabilityRequestNegativeReply(
+    const Address& peer, hci::Status reason) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
 
   security_manager_.InvalidateIoCapabilities();
 
-  SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
-      IoCapabilityNegativeResponseBuilder::Create(static_cast<uint8_t>(reason)), properties_.GetAddress(), peer));
+  auto packet = model::packets::IoCapabilityNegativeResponseBuilder::Create(
+      properties_.GetAddress(), peer, static_cast<uint8_t>(reason));
+  SendLinkLayerPacket(std::move(packet));
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::UserConfirmationRequestReply(const Address& peer) {
+bluetooth::hci::ErrorCode LinkLayerController::UserConfirmationRequestReply(
+    const Address& peer) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
   // TODO: Key could be calculated here.
-  std::vector<uint8_t> key_vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+  std::array<uint8_t, 16> key_vec{1, 2,  3,  4,  5,  6,  7,  8,
+                                  9, 10, 11, 12, 13, 14, 15, 16};
   security_manager_.WriteKey(peer, key_vec);
 
   security_manager_.AuthenticationRequestFinished();
 
-  schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
-  return hci::Status::SUCCESS;
+  ScheduleTask(milliseconds(5), [this, peer, key_vec]() {
+    send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create(
+        peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P256));
+  });
+
+  ScheduleTask(milliseconds(15),
+               [this, peer]() { AuthenticateRemoteStage2(peer); });
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::UserConfirmationRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode
+LinkLayerController::UserConfirmationRequestNegativeReply(const Address& peer) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value) {
+bluetooth::hci::ErrorCode LinkLayerController::UserPasskeyRequestReply(
+    const Address& peer, uint32_t numeric_value) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
-  LOG_INFO(LOG_TAG, "TODO:Do something with the passkey %06d", numeric_value);
-  return hci::Status::SUCCESS;
+  LOG_INFO("TODO:Do something with the passkey %06d", numeric_value);
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::UserPasskeyRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode LinkLayerController::UserPasskeyRequestNegativeReply(
+    const Address& peer) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
-                                                           const std::vector<uint8_t>& r) {
+bluetooth::hci::ErrorCode LinkLayerController::RemoteOobDataRequestReply(
+    const Address& peer, const std::vector<uint8_t>& c,
+    const std::vector<uint8_t>& r) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
-  LOG_INFO(LOG_TAG, "TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]);
-  return hci::Status::SUCCESS;
+  LOG_INFO("TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]);
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::RemoteOobDataRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode
+LinkLayerController::RemoteOobDataRequestNegativeReply(const Address& peer) {
   if (security_manager_.GetAuthenticationAddress() != peer) {
-    return hci::Status::AUTHENTICATION_FAILURE;
+    return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
   }
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::HandleAuthenticationRequest(const Address& address, uint16_t handle) {
   if (simple_pairing_mode_enabled_ == true) {
     security_manager_.AuthenticationRequest(address, handle);
-    send_event_(EventPacketBuilder::CreateLinkKeyRequestEvent(address)->ToVector());
+    auto packet = bluetooth::hci::LinkKeyRequestBuilder::Create(address);
+    send_event_(std::move(packet));
   } else {  // Should never happen for our phones
     // Check for a key, try to authenticate, ask for a PIN.
-    send_event_(
-        EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::AUTHENTICATION_FAILURE, handle)->ToVector());
+    auto packet = bluetooth::hci::AuthenticationCompleteBuilder::Create(
+        bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE, handle);
+    send_event_(std::move(packet));
   }
 }
 
-hci::Status LinkLayerController::AuthenticationRequested(uint16_t handle) {
-  if (!classic_connections_.HasHandle(handle)) {
-    LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::AuthenticationRequested(
+    uint16_t handle) {
+  if (!connections_.HasHandle(handle)) {
+    LOG_INFO("Authentication Requested for unknown handle %04x", handle);
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
-  Address remote = classic_connections_.GetAddress(handle);
+  Address remote = connections_.GetAddress(handle);
 
-  schedule_task_(milliseconds(5), [this, remote, handle]() { HandleAuthenticationRequest(remote, handle); });
+  ScheduleTask(milliseconds(5), [this, remote, handle]() { HandleAuthenticationRequest(remote, handle); });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::HandleSetConnectionEncryption(const Address& peer, uint16_t handle,
                                                         uint8_t encryption_enable) {
   // TODO: Block ACL traffic or at least guard against it
 
-  if (classic_connections_.IsEncrypted(handle) && encryption_enable) {
-    send_event_(
-        EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, encryption_enable)->ToVector());
+  if (connections_.IsEncrypted(handle) && encryption_enable) {
+    auto packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+        bluetooth::hci::ErrorCode::SUCCESS, handle,
+        static_cast<bluetooth::hci::EncryptionEnabled>(encryption_enable));
+    send_event_(std::move(packet));
     return;
   }
 
-  SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnection(
-      EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+  uint16_t count = security_manager_.ReadKey(peer);
+  if (count == 0) {
+    LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str());
+    return;
+  }
+  auto array = security_manager_.GetKey(peer);
+  std::vector<uint8_t> key_vec{array.begin(), array.end()};
+  auto packet = model::packets::EncryptConnectionBuilder::Create(
+      properties_.GetAddress(), peer, key_vec);
+  SendLinkLayerPacket(std::move(packet));
 }
 
-hci::Status LinkLayerController::SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable) {
-  if (!classic_connections_.HasHandle(handle)) {
-    LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::SetConnectionEncryption(
+    uint16_t handle, uint8_t encryption_enable) {
+  if (!connections_.HasHandle(handle)) {
+    LOG_INFO("Set Connection Encryption for unknown handle %04x", handle);
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
-  if (classic_connections_.IsEncrypted(handle) && !encryption_enable) {
-    return hci::Status::ENCRYPTION_MODE_NOT_ACCEPTABLE;
+  if (connections_.IsEncrypted(handle) && !encryption_enable) {
+    return bluetooth::hci::ErrorCode::ENCRYPTION_MODE_NOT_ACCEPTABLE;
   }
-  Address remote = classic_connections_.GetAddress(handle);
+  Address remote = connections_.GetAddress(handle);
 
-  schedule_task_(milliseconds(5), [this, remote, handle, encryption_enable]() {
+  if (security_manager_.ReadKey(remote) == 0) {
+    return bluetooth::hci::ErrorCode::PIN_OR_KEY_MISSING;
+  }
+
+  ScheduleTask(milliseconds(5), [this, remote, handle, encryption_enable]() {
     HandleSetConnectionEncryption(remote, handle, encryption_enable);
   });
-
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::AcceptConnectionRequest(const Address& addr, bool try_role_switch) {
-  if (!classic_connections_.HasPendingConnection(addr)) {
-    LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::AcceptConnectionRequest(
+    const Address& addr, bool try_role_switch) {
+  if (!connections_.HasPendingConnection(addr)) {
+    LOG_INFO("%s: No pending connection for %s", __func__, addr.ToString().c_str());
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
-  LOG_INFO(LOG_TAG, "%s: Accept in 200ms", __func__);
-  schedule_task_(milliseconds(200), [this, addr, try_role_switch]() {
-    LOG_INFO(LOG_TAG, "%s: Accepted", __func__);
+  LOG_INFO("%s: Accept in 200ms", __func__);
+  ScheduleTask(milliseconds(200), [this, addr, try_role_switch]() {
+    LOG_INFO("%s: Accepted", __func__);
     MakeSlaveConnection(addr, try_role_switch);
   });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::MakeSlaveConnection(const Address& addr, bool try_role_switch) {
-  std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapPageResponse(
-      PageResponseBuilder::Create(try_role_switch), properties_.GetAddress(), addr);
-  LOG_INFO(LOG_TAG, "%s sending page response to %s", __func__, addr.ToString().c_str());
-  SendLinkLayerPacket(to_send);
+  LOG_INFO("%s sending page response to %s", __func__, addr.ToString().c_str());
+  auto to_send = model::packets::PageResponseBuilder::Create(
+      properties_.GetAddress(), addr, try_role_switch);
+  SendLinkLayerPacket(std::move(to_send));
 
-  uint16_t handle = classic_connections_.CreateConnection(addr);
+  uint16_t handle = connections_.CreateConnection(addr);
   if (handle == acl::kReservedHandle) {
-    LOG_INFO(LOG_TAG, "%s CreateConnection failed", __func__);
+    LOG_INFO("%s CreateConnection failed", __func__);
     return;
   }
-  LOG_INFO(LOG_TAG, "%s CreateConnection returned handle 0x%x", __func__, handle);
-  send_event_(
-      EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle, addr, hci::LinkType::ACL, false)
-          ->ToVector());
+  LOG_INFO("%s CreateConnection returned handle 0x%x", __func__, handle);
+  auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle, addr,
+      bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet));
 }
 
-hci::Status LinkLayerController::RejectConnectionRequest(const Address& addr, uint8_t reason) {
-  if (!classic_connections_.HasPendingConnection(addr)) {
-    LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::RejectConnectionRequest(
+    const Address& addr, uint8_t reason) {
+  if (!connections_.HasPendingConnection(addr)) {
+    LOG_INFO("%s: No pending connection for %s", __func__, addr.ToString().c_str());
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
-  LOG_INFO(LOG_TAG, "%s: Reject in 200ms", __func__);
-  schedule_task_(milliseconds(200), [this, addr, reason]() {
-    LOG_INFO(LOG_TAG, "%s: Reject", __func__);
-    RejectSlaveConnection(addr, reason);
-  });
+  ScheduleTask(milliseconds(200),
+               [this, addr, reason]() { RejectSlaveConnection(addr, reason); });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::RejectSlaveConnection(const Address& addr, uint8_t reason) {
-  std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapPageReject(
-      PageRejectBuilder::Create(reason), properties_.GetAddress(), addr);
-  LOG_INFO(LOG_TAG, "%s sending page reject to %s", __func__, addr.ToString().c_str());
-  SendLinkLayerPacket(to_send);
+  auto to_send = model::packets::PageRejectBuilder::Create(
+      properties_.GetAddress(), addr, reason);
+  LOG_INFO("%s sending page reject to %s (reason 0x%02hhx)", __func__,
+           addr.ToString().c_str(), reason);
+  SendLinkLayerPacket(std::move(to_send));
 
-  CHECK(reason >= 0x0d && reason <= 0x0f);
-  send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reason), 0xeff, addr,
-                                                                hci::LinkType::ACL, false)
-                  ->ToVector());
+  auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+      static_cast<bluetooth::hci::ErrorCode>(reason), 0xeff, addr,
+      bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+  send_event_(std::move(packet));
 }
 
-hci::Status LinkLayerController::CreateConnection(const Address& addr, uint16_t, uint8_t, uint16_t,
-                                                  uint8_t allow_role_switch) {
-  if (!classic_connections_.CreatePendingConnection(addr)) {
-    return hci::Status::CONTROLLER_BUSY;
+bluetooth::hci::ErrorCode LinkLayerController::CreateConnection(
+    const Address& addr, uint16_t, uint8_t, uint16_t,
+    uint8_t allow_role_switch) {
+  if (!connections_.CreatePendingConnection(
+          addr, properties_.GetAuthenticationEnable() == 1)) {
+    return bluetooth::hci::ErrorCode::CONTROLLER_BUSY;
   }
+  auto page = model::packets::PageBuilder::Create(
+      properties_.GetAddress(), addr, properties_.GetClassOfDevice(),
+      allow_role_switch);
+  SendLinkLayerPacket(std::move(page));
 
-  std::unique_ptr<PageBuilder> page = PageBuilder::Create(properties_.GetClassOfDevice(), allow_role_switch);
-  SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPage(std::move(page), properties_.GetAddress(), addr));
-
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::CreateConnectionCancel(const Address& addr) {
-  if (!classic_connections_.CancelPendingConnection(addr)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::CreateConnectionCancel(
+    const Address& addr) {
+  if (!connections_.CancelPendingConnection(addr)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) {
+bluetooth::hci::ErrorCode LinkLayerController::Disconnect(uint16_t handle,
+                                                          uint8_t reason) {
   // TODO: Handle LE
-  if (!classic_connections_.HasHandle(handle)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
 
-  const Address& remote = classic_connections_.GetAddress(handle);
-  std::shared_ptr<LinkLayerPacketBuilder> to_send =
-      LinkLayerPacketBuilder::WrapDisconnect(DisconnectBuilder::Create(reason), properties_.GetAddress(), remote);
-  SendLinkLayerPacket(to_send);
-  CHECK(classic_connections_.Disconnect(handle)) << "Disconnecting " << handle;
+  const Address& remote = connections_.GetAddress(handle);
+  auto packet = model::packets::DisconnectBuilder::Create(
+      properties_.GetAddress(), remote, reason);
+  SendLinkLayerPacket(std::move(packet));
+  ASSERT_LOG(connections_.Disconnect(handle), "Disconnecting %hx", handle);
 
-  schedule_task_(milliseconds(20), [this, handle]() {
+  ScheduleTask(milliseconds(20), [this, handle]() {
     DisconnectCleanup(handle, static_cast<uint8_t>(hci::Status::CONNECTION_TERMINATED_BY_LOCAL_HOST));
   });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::DisconnectCleanup(uint16_t handle, uint8_t reason) {
   // TODO: Clean up other connection state.
-  send_event_(EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status::SUCCESS, handle, reason)->ToVector());
+  auto packet = bluetooth::hci::DisconnectionCompleteBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle,
+      static_cast<bluetooth::hci::ErrorCode>(reason));
+  send_event_(std::move(packet));
 }
 
-hci::Status LinkLayerController::ChangeConnectionPacketType(uint16_t handle, uint16_t types) {
-  if (!classic_connections_.HasHandle(handle)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::ChangeConnectionPacketType(
+    uint16_t handle, uint16_t types) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
-  std::unique_ptr<EventPacketBuilder> packet =
-      EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status::SUCCESS, handle, types);
-  std::shared_ptr<std::vector<uint8_t>> raw_packet = packet->ToVector();
-  if (schedule_task_) {
-    schedule_task_(milliseconds(20), [this, raw_packet]() { send_event_(raw_packet); });
-  } else {
-    send_event_(raw_packet);
-  }
+  auto packet = bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create(
+      bluetooth::hci::ErrorCode::SUCCESS, handle, types);
+  std::shared_ptr<bluetooth::hci::ConnectionPacketTypeChangedBuilder>
+      shared_packet = std::move(packet);
+  ScheduleTask(milliseconds(20), [this, shared_packet]() {
+    send_event_(std::move(shared_packet));
+  });
 
-  return hci::Status::SUCCESS;
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
-hci::Status LinkLayerController::WriteLinkPolicySettings(uint16_t handle, uint16_t) {
-  if (!classic_connections_.HasHandle(handle)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::ChangeConnectionLinkKey(
+    uint16_t handle) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
-  return hci::Status::SUCCESS;
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
 }
 
-hci::Status LinkLayerController::WriteLinkSupervisionTimeout(uint16_t handle, uint16_t) {
-  if (!classic_connections_.HasHandle(handle)) {
-    return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::MasterLinkKey(
+    uint8_t /* key_flag */) {
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::HoldMode(
+    uint16_t handle, uint16_t hold_mode_max_interval,
+    uint16_t hold_mode_min_interval) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
   }
-  return hci::Status::SUCCESS;
+
+  if (hold_mode_max_interval < hold_mode_min_interval) {
+    return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+  }
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::SniffMode(
+    uint16_t handle, uint16_t sniff_max_interval, uint16_t sniff_min_interval,
+    uint16_t sniff_attempt, uint16_t sniff_timeout) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+
+  if (sniff_max_interval < sniff_min_interval || sniff_attempt < 0x0001 || sniff_attempt > 0x7FFF ||
+      sniff_timeout > 0x7FFF) {
+    return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+  }
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::ExitSniffMode(uint16_t handle) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::QosSetup(
+    uint16_t handle, uint8_t service_type, uint32_t /* token_rate */,
+    uint32_t /* peak_bandwidth */, uint32_t /* latency */,
+    uint32_t /* delay_variation */) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+
+  if (service_type > 0x02) {
+    return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+  }
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::SwitchRole(Address /* bd_addr */,
+                                                          uint8_t /* role */) {
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::WriteLinkPolicySettings(
+    uint16_t handle, uint16_t) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+  return bluetooth::hci::ErrorCode::SUCCESS;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::FlowSpecification(
+    uint16_t handle, uint8_t flow_direction, uint8_t service_type,
+    uint32_t /* token_rate */, uint32_t /* token_bucket_size */,
+    uint32_t /* peak_bandwidth */, uint32_t /* access_latency */) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+
+  if (flow_direction > 0x01 || service_type > 0x02) {
+    return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+  }
+
+  // TODO: implement real logic
+  return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::WriteLinkSupervisionTimeout(
+    uint16_t handle, uint16_t) {
+  if (!connections_.HasHandle(handle)) {
+    return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+  }
+  return bluetooth::hci::ErrorCode::SUCCESS;
 }
 
 void LinkLayerController::LeWhiteListClear() {
   le_white_list_.clear();
 }
 
+void LinkLayerController::LeResolvingListClear() { le_resolving_list_.clear(); }
+
 void LinkLayerController::LeWhiteListAddDevice(Address addr, uint8_t addr_type) {
   std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type);
   for (auto dev : le_white_list_) {
@@ -1058,6 +1531,30 @@
   le_white_list_.emplace_back(new_tuple);
 }
 
+void LinkLayerController::LeResolvingListAddDevice(
+    Address addr, uint8_t addr_type, std::array<uint8_t, kIrk_size> peerIrk,
+    std::array<uint8_t, kIrk_size> localIrk) {
+  std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>,
+             std::array<uint8_t, kIrk_size>>
+      new_tuple = std::make_tuple(addr, addr_type, peerIrk, localIrk);
+  for (size_t i = 0; i < le_white_list_.size(); i++) {
+    auto curr = le_white_list_[i];
+    if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+      le_resolving_list_[i] = new_tuple;
+      return;
+    }
+  }
+  le_resolving_list_.emplace_back(new_tuple);
+}
+
+void LinkLayerController::LeSetPrivacyMode(uint8_t address_type, Address addr,
+                                           uint8_t mode) {
+  // set mode for addr
+  LOG_INFO("address type = %d ", address_type);
+  LOG_INFO("address = %s ", addr.ToString().c_str());
+  LOG_INFO("mode = %d ", mode);
+}
+
 void LinkLayerController::LeWhiteListRemoveDevice(Address addr, uint8_t addr_type) {
   // TODO: Add checks to see if advertising, scanning, or a connection request
   // with the white list is ongoing.
@@ -1069,6 +1566,18 @@
   }
 }
 
+void LinkLayerController::LeResolvingListRemoveDevice(Address addr,
+                                                      uint8_t addr_type) {
+  // TODO: Add checks to see if advertising, scanning, or a connection request
+  // with the white list is ongoing.
+  for (size_t i = 0; i < le_white_list_.size(); i++) {
+    auto curr = le_white_list_[i];
+    if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+      le_resolving_list_.erase(le_resolving_list_.begin() + i);
+    }
+  }
+}
+
 bool LinkLayerController::LeWhiteListContainsDevice(Address addr, uint8_t addr_type) {
   std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type);
   for (size_t i = 0; i < le_white_list_.size(); i++) {
@@ -1079,39 +1588,56 @@
   return false;
 }
 
+bool LinkLayerController::LeResolvingListContainsDevice(Address addr,
+                                                        uint8_t addr_type) {
+  for (size_t i = 0; i < le_white_list_.size(); i++) {
+    auto curr = le_white_list_[i];
+    if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool LinkLayerController::LeWhiteListFull() {
   return le_white_list_.size() >= properties_.GetLeWhiteListSize();
 }
 
+bool LinkLayerController::LeResolvingListFull() {
+  return le_resolving_list_.size() >= properties_.GetLeResolvingListSize();
+}
+
 void LinkLayerController::Reset() {
   inquiry_state_ = Inquiry::InquiryState::STANDBY;
   last_inquiry_ = steady_clock::now();
   le_scan_enable_ = 0;
+  le_advertising_enable_ = 0;
   le_connect_ = 0;
 }
 
 void LinkLayerController::PageScan() {}
 
 void LinkLayerController::StartInquiry(milliseconds timeout) {
-  schedule_task_(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); });
+  ScheduleTask(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); });
   inquiry_state_ = Inquiry::InquiryState::INQUIRY;
-  LOG_INFO(LOG_TAG, "InquiryState = %d ", static_cast<int>(inquiry_state_));
 }
 
 void LinkLayerController::InquiryCancel() {
-  CHECK(inquiry_state_ == Inquiry::InquiryState::INQUIRY);
+  ASSERT(inquiry_state_ == Inquiry::InquiryState::INQUIRY);
   inquiry_state_ = Inquiry::InquiryState::STANDBY;
 }
 
 void LinkLayerController::InquiryTimeout() {
   if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) {
     inquiry_state_ = Inquiry::InquiryState::STANDBY;
-    send_event_(EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status::SUCCESS)->ToVector());
+    auto packet = bluetooth::hci::InquiryCompleteBuilder::Create(
+        bluetooth::hci::ErrorCode::SUCCESS);
+    send_event_(std::move(packet));
   }
 }
 
 void LinkLayerController::SetInquiryMode(uint8_t mode) {
-  inquiry_mode_ = static_cast<Inquiry::InquiryType>(mode);
+  inquiry_mode_ = static_cast<model::packets::InquiryType>(mode);
 }
 
 void LinkLayerController::SetInquiryLAP(uint64_t lap) {
@@ -1127,11 +1653,10 @@
   if (duration_cast<milliseconds>(now - last_inquiry_) < milliseconds(2000)) {
     return;
   }
-  LOG_INFO(LOG_TAG, "Inquiry ");
-  std::unique_ptr<InquiryBuilder> inquiry = InquiryBuilder::Create(inquiry_mode_);
-  std::shared_ptr<LinkLayerPacketBuilder> to_send =
-      LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry), properties_.GetAddress());
-  SendLinkLayerPacket(to_send);
+
+  auto packet = model::packets::InquiryBuilder::Create(
+      properties_.GetAddress(), Address::kEmpty, inquiry_mode_);
+  SendLinkLayerPacket(std::move(packet));
   last_inquiry_ = now;
 }
 
@@ -1143,18 +1668,4 @@
   page_scans_enabled_ = enable;
 }
 
-/* TODO: Connection handling
-  // TODO: Handle in the link manager.
-  uint16_t handle = LeGetHandle();
-
-  std::shared_ptr<Connection> new_connection =
-      std::make_shared<Connection>(peer, handle);
-  connections_.push_back(new_connection);
-  peer->SetConnection(new_connection);
-
-  send_event_(EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
-      hci::Status::SUCCESS, handle, 0x00,  // role
-      le_peer_address_type_, le_peer_address_, Address::kEmpty,
-  Address::kEmpty, 0x0024, 0x0000, 0x01f4)->ToVector());
-*/
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
index 3828891..cffc935 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -17,77 +17,110 @@
 #pragma once
 
 #include "acl_connection_handler.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
 #include "include/hci.h"
 #include "include/inquiry.h"
-#include "include/link.h"
 #include "include/phy.h"
 #include "model/devices/device_properties.h"
 #include "model/setup/async_manager.h"
-#include "packets/hci/acl_packet_view.h"
-#include "packets/hci/sco_packet_view.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
+#include "packets/packet_view.h"
 #include "security_manager.h"
-#include "types/address.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 class LinkLayerController {
  public:
+  static constexpr size_t kIrk_size = 16;
+
   LinkLayerController(const DeviceProperties& properties) : properties_(properties) {}
-  hci::Status SendCommandToRemoteByAddress(hci::OpCode opcode, packets::PacketView<true> args, const Address& remote,
-                                           bool use_public_address);
-  hci::Status SendCommandToRemoteByHandle(hci::OpCode opcode, packets::PacketView<true> args, uint16_t handle);
-  hci::Status SendScoToRemote(packets::ScoPacketView sco_packet);
-  hci::Status SendAclToRemote(packets::AclPacketView acl_packet);
+  bluetooth::hci::ErrorCode SendCommandToRemoteByAddress(
+      bluetooth::hci::OpCode opcode, packets::PacketView<true> args,
+      const Address& remote);
+  bluetooth::hci::ErrorCode SendCommandToRemoteByHandle(
+      bluetooth::hci::OpCode opcode, packets::PacketView<true> args,
+      uint16_t handle);
+  hci::Status SendScoToRemote(bluetooth::hci::ScoPacketView sco_packet);
+  hci::Status SendAclToRemote(bluetooth::hci::AclPacketView acl_packet);
 
   void WriteSimplePairingMode(bool enabled);
   void StartSimplePairing(const Address& address);
   void AuthenticateRemoteStage1(const Address& address, PairingType pairing_type);
   void AuthenticateRemoteStage2(const Address& address);
-  hci::Status LinkKeyRequestReply(const Address& address, packets::PacketView<true> key);
-  hci::Status LinkKeyRequestNegativeReply(const Address& address);
-  hci::Status IoCapabilityRequestReply(const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
-                                       uint8_t authentication_requirements);
-  hci::Status IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason);
-  hci::Status UserConfirmationRequestReply(const Address& peer);
-  hci::Status UserConfirmationRequestNegativeReply(const Address& peer);
-  hci::Status UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value);
-  hci::Status UserPasskeyRequestNegativeReply(const Address& peer);
-  hci::Status RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
-                                        const std::vector<uint8_t>& r);
-  hci::Status RemoteOobDataRequestNegativeReply(const Address& peer);
+  bluetooth::hci::ErrorCode LinkKeyRequestReply(
+      const Address& address, const std::array<uint8_t, 16>& key);
+  bluetooth::hci::ErrorCode LinkKeyRequestNegativeReply(const Address& address);
+  bluetooth::hci::ErrorCode IoCapabilityRequestReply(
+      const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
+      uint8_t authentication_requirements);
+  bluetooth::hci::ErrorCode IoCapabilityRequestNegativeReply(
+      const Address& peer, hci::Status reason);
+  bluetooth::hci::ErrorCode UserConfirmationRequestReply(const Address& peer);
+  bluetooth::hci::ErrorCode UserConfirmationRequestNegativeReply(
+      const Address& peer);
+  bluetooth::hci::ErrorCode UserPasskeyRequestReply(const Address& peer,
+                                                    uint32_t numeric_value);
+  bluetooth::hci::ErrorCode UserPasskeyRequestNegativeReply(
+      const Address& peer);
+  bluetooth::hci::ErrorCode RemoteOobDataRequestReply(
+      const Address& peer, const std::vector<uint8_t>& c,
+      const std::vector<uint8_t>& r);
+  bluetooth::hci::ErrorCode RemoteOobDataRequestNegativeReply(
+      const Address& peer);
   void HandleSetConnectionEncryption(const Address& address, uint16_t handle, uint8_t encryption_enable);
-  hci::Status SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable);
+  bluetooth::hci::ErrorCode SetConnectionEncryption(uint16_t handle,
+                                                    uint8_t encryption_enable);
   void HandleAuthenticationRequest(const Address& address, uint16_t handle);
-  hci::Status AuthenticationRequested(uint16_t handle);
+  bluetooth::hci::ErrorCode AuthenticationRequested(uint16_t handle);
 
-  hci::Status AcceptConnectionRequest(const Address& addr, bool try_role_switch);
+  bluetooth::hci::ErrorCode AcceptConnectionRequest(const Address& addr,
+                                                    bool try_role_switch);
   void MakeSlaveConnection(const Address& addr, bool try_role_switch);
-  hci::Status RejectConnectionRequest(const Address& addr, uint8_t reason);
+  bluetooth::hci::ErrorCode RejectConnectionRequest(const Address& addr,
+                                                    uint8_t reason);
   void RejectSlaveConnection(const Address& addr, uint8_t reason);
-  hci::Status CreateConnection(const Address& addr, uint16_t packet_type, uint8_t page_scan_mode, uint16_t clock_offset,
-                               uint8_t allow_role_switch);
-  hci::Status CreateConnectionCancel(const Address& addr);
-  hci::Status Disconnect(uint16_t handle, uint8_t reason);
+  bluetooth::hci::ErrorCode CreateConnection(const Address& addr,
+                                             uint16_t packet_type,
+                                             uint8_t page_scan_mode,
+                                             uint16_t clock_offset,
+                                             uint8_t allow_role_switch);
+  bluetooth::hci::ErrorCode CreateConnectionCancel(const Address& addr);
+  bluetooth::hci::ErrorCode Disconnect(uint16_t handle, uint8_t reason);
 
  private:
   void DisconnectCleanup(uint16_t handle, uint8_t reason);
 
  public:
-  void IncomingPacket(packets::LinkLayerPacketView incoming);
+  void IncomingPacket(model::packets::LinkLayerPacketView incoming);
 
   void TimerTick();
 
-  // Set the callbacks for sending packets to the HCI.
-  void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+  AsyncTaskId ScheduleTask(std::chrono::milliseconds delay_ms, const TaskCallback& task);
 
-  void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
+  void CancelScheduledTask(AsyncTaskId task);
+
+  // Set the callbacks for sending packets to the HCI.
+  void RegisterEventChannel(
+      const std::function<void(
+          std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>& send_event);
+
+  void RegisterAclChannel(
+      const std::function<
+          void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>& send_acl);
 
   void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
 
+  void RegisterIsoChannel(
+      const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+          send_iso);
+
   void RegisterRemoteChannel(
-      const std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type)>& send_to_remote);
+      const std::function<void(
+          std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>&
+          send_to_remote);
 
   // Set the callbacks for scheduling tasks.
   void RegisterTaskScheduler(
@@ -104,11 +137,31 @@
   void PageScan();
   void Connections();
 
+  void LeAdvertising();
+
+  void HandleLeConnection(Address addr, uint8_t addr_type, uint8_t own_addr_type, uint8_t role,
+                          uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout);
+
   void LeWhiteListClear();
   void LeWhiteListAddDevice(Address addr, uint8_t addr_type);
   void LeWhiteListRemoveDevice(Address addr, uint8_t addr_type);
   bool LeWhiteListContainsDevice(Address addr, uint8_t addr_type);
   bool LeWhiteListFull();
+  void LeResolvingListClear();
+  void LeResolvingListAddDevice(Address addr, uint8_t addr_type,
+                                std::array<uint8_t, kIrk_size> peerIrk,
+                                std::array<uint8_t, kIrk_size> localIrk);
+  void LeResolvingListRemoveDevice(Address addr, uint8_t addr_type);
+  bool LeResolvingListContainsDevice(Address addr, uint8_t addr_type);
+  bool LeResolvingListFull();
+  void LeSetPrivacyMode(uint8_t address_type, Address addr, uint8_t mode);
+
+  bluetooth::hci::ErrorCode SetLeAdvertisingEnable(
+      uint8_t le_advertising_enable) {
+    le_advertising_enable_ = le_advertising_enable;
+    // TODO: Check properties and return errors
+    return bluetooth::hci::ErrorCode::SUCCESS;
+  }
 
   void SetLeScanEnable(uint8_t le_scan_enable) {
     le_scan_enable_ = le_scan_enable;
@@ -131,9 +184,9 @@
   void SetLeAddressType(uint8_t le_address_type) {
     le_address_type_ = le_address_type;
   }
-  hci::Status SetLeConnect(bool le_connect) {
+  bluetooth::hci::ErrorCode SetLeConnect(bool le_connect) {
     le_connect_ = le_connect;
-    return hci::Status::SUCCESS;
+    return bluetooth::hci::ErrorCode::SUCCESS;
   }
   void SetLeConnectionIntervalMin(uint16_t min) {
     le_connection_interval_min_ = min;
@@ -175,38 +228,93 @@
   void SetInquiryScanEnable(bool enable);
   void SetPageScanEnable(bool enable);
 
-  hci::Status ChangeConnectionPacketType(uint16_t handle, uint16_t types);
-  hci::Status WriteLinkPolicySettings(uint16_t handle, uint16_t settings);
-  hci::Status WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout);
+  bluetooth::hci::ErrorCode ChangeConnectionPacketType(uint16_t handle,
+                                                       uint16_t types);
+  bluetooth::hci::ErrorCode ChangeConnectionLinkKey(uint16_t handle);
+  bluetooth::hci::ErrorCode MasterLinkKey(uint8_t key_flag);
+  bluetooth::hci::ErrorCode HoldMode(uint16_t handle,
+                                     uint16_t hold_mode_max_interval,
+                                     uint16_t hold_mode_min_interval);
+  bluetooth::hci::ErrorCode SniffMode(uint16_t handle,
+                                      uint16_t sniff_max_interval,
+                                      uint16_t sniff_min_interval,
+                                      uint16_t sniff_attempt,
+                                      uint16_t sniff_timeout);
+  bluetooth::hci::ErrorCode ExitSniffMode(uint16_t handle);
+  bluetooth::hci::ErrorCode QosSetup(uint16_t handle, uint8_t service_type,
+                                     uint32_t token_rate,
+                                     uint32_t peak_bandwidth, uint32_t latency,
+                                     uint32_t delay_variation);
+  bluetooth::hci::ErrorCode SwitchRole(Address bd_addr, uint8_t role);
+  bluetooth::hci::ErrorCode WriteLinkPolicySettings(uint16_t handle,
+                                                    uint16_t settings);
+  bluetooth::hci::ErrorCode FlowSpecification(
+      uint16_t handle, uint8_t flow_direction, uint8_t service_type,
+      uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth,
+      uint32_t access_latency);
+  bluetooth::hci::ErrorCode WriteLinkSupervisionTimeout(uint16_t handle,
+                                                        uint16_t timeout);
 
  protected:
-  void SendLELinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
-  void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
-  void IncomingAclPacket(packets::LinkLayerPacketView packet);
-  void IncomingAclAckPacket(packets::LinkLayerPacketView packet);
-  void IncomingCommandPacket(packets::LinkLayerPacketView packet);
-  void IncomingCreateConnectionPacket(packets::LinkLayerPacketView packet);
-  void IncomingDisconnectPacket(packets::LinkLayerPacketView packet);
-  void IncomingEncryptConnection(packets::LinkLayerPacketView packet);
-  void IncomingEncryptConnectionResponse(packets::LinkLayerPacketView packet);
-  void IncomingInquiryPacket(packets::LinkLayerPacketView packet);
-  void IncomingInquiryResponsePacket(packets::LinkLayerPacketView packet);
-  void IncomingIoCapabilityRequestPacket(packets::LinkLayerPacketView packet);
-  void IncomingIoCapabilityResponsePacket(packets::LinkLayerPacketView packet);
-  void IncomingIoCapabilityNegativeResponsePacket(packets::LinkLayerPacketView packet);
-  void IncomingLeAdvertisementPacket(packets::LinkLayerPacketView packet);
-  void IncomingLeScanPacket(packets::LinkLayerPacketView packet);
-  void IncomingLeScanResponsePacket(packets::LinkLayerPacketView packet);
-  void IncomingPagePacket(packets::LinkLayerPacketView packet);
-  void IncomingPageRejectPacket(packets::LinkLayerPacketView packet);
-  void IncomingPageResponsePacket(packets::LinkLayerPacketView packet);
-  void IncomingResponsePacket(packets::LinkLayerPacketView packet);
+  void SendLeLinkLayerPacket(
+      std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet);
+  void SendLinkLayerPacket(
+      std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet);
+  void IncomingAclPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingAclAckPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingCreateConnectionPacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingDisconnectPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingEncryptConnection(model::packets::LinkLayerPacketView packet);
+  void IncomingEncryptConnectionResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingInquiryPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingInquiryResponsePacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingIoCapabilityRequestPacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingIoCapabilityResponsePacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingIoCapabilityNegativeResponsePacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingLeAdvertisementPacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingLeConnectPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingLeConnectCompletePacket(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingLeScanPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView packet);
+  void IncomingPagePacket(model::packets::LinkLayerPacketView packet);
+  void IncomingPageRejectPacket(model::packets::LinkLayerPacketView packet);
+  void IncomingPageResponsePacket(model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteLmpFeatures(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteLmpFeaturesResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteSupportedFeatures(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteSupportedFeaturesResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteExtendedFeatures(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteExtendedFeaturesResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteVersion(model::packets::LinkLayerPacketView packet);
+  void IncomingReadRemoteVersionResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingReadClockOffset(model::packets::LinkLayerPacketView packet);
+  void IncomingReadClockOffsetResponse(
+      model::packets::LinkLayerPacketView packet);
+  void IncomingRemoteNameRequest(model::packets::LinkLayerPacketView packet);
+  void IncomingRemoteNameRequestResponse(
+      model::packets::LinkLayerPacketView packet);
 
  private:
   const DeviceProperties& properties_;
-  AclConnectionHandler classic_connections_;
+  AclConnectionHandler connections_;
   // Add timestamps?
-  std::vector<std::shared_ptr<packets::LinkLayerPacketBuilder>> commands_awaiting_responses_;
+  std::vector<std::shared_ptr<model::packets::LinkLayerPacketBuilder>>
+      commands_awaiting_responses_;
 
   // Timing related state
   std::vector<AsyncTaskId> controller_events_;
@@ -220,19 +328,30 @@
   std::function<void(AsyncTaskId)> cancel_task_;
 
   // Callbacks to send packets back to the HCI.
-  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
-  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+  std::function<void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>
+      send_acl_;
+  std::function<void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>
+      send_event_;
   std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+  std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_iso_;
 
   // Callback to send packets to remote devices.
-  std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type phy_type)> send_to_remote_;
+  std::function<void(std::shared_ptr<model::packets::LinkLayerPacketBuilder>,
+                     Phy::Type phy_type)>
+      send_to_remote_;
 
   // LE state
   std::vector<uint8_t> le_event_mask_;
 
   std::vector<std::tuple<Address, uint8_t>> le_white_list_;
+  std::vector<std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>,
+                         std::array<uint8_t, kIrk_size>>>
+      le_resolving_list_;
 
-  uint8_t le_scan_enable_;
+  uint8_t le_advertising_enable_{false};
+  std::chrono::steady_clock::time_point last_le_advertisement_;
+
+  uint8_t le_scan_enable_{false};
   uint8_t le_scan_type_;
   uint16_t le_scan_interval_;
   uint16_t le_scan_window_;
@@ -240,7 +359,7 @@
   uint8_t le_scan_filter_duplicates_;
   uint8_t le_address_type_;
 
-  bool le_connect_;
+  bool le_connect_{false};
   uint16_t le_connection_interval_min_;
   uint16_t le_connection_interval_max_;
   uint16_t le_connection_latency_;
@@ -256,7 +375,7 @@
 
   SecurityManager security_manager_{10};
   std::chrono::steady_clock::time_point last_inquiry_;
-  Inquiry::InquiryType inquiry_mode_;
+  model::packets::InquiryType inquiry_mode_;
   Inquiry::InquiryState inquiry_state_;
   uint64_t inquiry_lap_;
   uint8_t inquiry_max_responses_;
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
index 6ab1351..38b9e64 100644
--- a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "security_manager"
-
 #include "security_manager.h"
 
-#include "base/logging.h"
+#include "os/log.h"
 
 using std::vector;
 
@@ -46,7 +44,8 @@
   return key_store_.count(addr.ToString());
 }
 
-uint16_t SecurityManager::WriteKey(const Address& addr, const std::vector<uint8_t>& key) {
+uint16_t SecurityManager::WriteKey(const Address& addr,
+                                   const std::array<uint8_t, 16>& key) {
   if (key_store_.size() >= max_keys_) {
     return 0;
   }
@@ -54,8 +53,9 @@
   return 1;
 }
 
-const std::vector<uint8_t>& SecurityManager::GetKey(const Address& addr) const {
-  CHECK(ReadKey(addr)) << "No such key";
+const std::array<uint8_t, 16>& SecurityManager::GetKey(
+    const Address& addr) const {
+  ASSERT_LOG(ReadKey(addr), "No such key");
   return key_store_.at(addr.ToString());
 }
 
@@ -83,7 +83,7 @@
 
 void SecurityManager::SetPeerIoCapability(const Address& addr, uint8_t io_capability, uint8_t oob_present_flag,
                                           uint8_t authentication_requirements) {
-  CHECK_EQ(addr, peer_address_);
+  ASSERT(addr == peer_address_);
   peer_capabilities_valid_ = true;
   if (io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT)) {
     peer_io_capability_ = static_cast<IoCapabilityType>(io_capability);
@@ -102,12 +102,12 @@
 
 void SecurityManager::SetLocalIoCapability(const Address& peer, uint8_t io_capability, uint8_t oob_present_flag,
                                            uint8_t authentication_requirements) {
-  CHECK_EQ(peer, peer_address_);
-  CHECK(io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT))
-      << "io_capability = " << io_capability;
-  CHECK(oob_present_flag <= 1) << "oob_present_flag = " << oob_present_flag;
-  CHECK(authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM))
-      << "authentication_requirements = " << authentication_requirements;
+  ASSERT(peer == peer_address_);
+  ASSERT_LOG(io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT), "io_capability = %d",
+             static_cast<int>(io_capability));
+  ASSERT_LOG(oob_present_flag <= 1, "oob_present_flag = %hhx ", oob_present_flag);
+  ASSERT_LOG(authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM),
+             "authentication_requirements = %d", static_cast<int>(authentication_requirements));
   host_io_capability_ = static_cast<IoCapabilityType>(io_capability);
   host_oob_present_flag_ = (oob_present_flag == 1);
   host_authentication_requirements_ = static_cast<AuthenticationType>(authentication_requirements);
@@ -132,7 +132,53 @@
   if (!(peer_requires_mitm || host_requires_mitm)) {
     return PairingType::AUTO_CONFIRMATION;
   }
-  return PairingType::INVALID;
+  LOG_INFO("%s: host does%s require peer does%s require MITM",
+           peer_address_.ToString().c_str(), host_requires_mitm ? "" : "n't",
+           peer_requires_mitm ? "" : "n't");
+  switch (peer_io_capability_) {
+    case IoCapabilityType::DISPLAY_ONLY:
+      switch (host_io_capability_) {
+        case IoCapabilityType::DISPLAY_ONLY:
+        case IoCapabilityType::DISPLAY_YES_NO:
+          return PairingType::AUTO_CONFIRMATION;
+        case IoCapabilityType::KEYBOARD_ONLY:
+          return PairingType::INPUT_PIN;
+        case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+          return PairingType::AUTO_CONFIRMATION;
+        default:
+          return PairingType::INVALID;
+      }
+    case IoCapabilityType::DISPLAY_YES_NO:
+      switch (host_io_capability_) {
+        case IoCapabilityType::DISPLAY_ONLY:
+          return PairingType::AUTO_CONFIRMATION;
+        case IoCapabilityType::DISPLAY_YES_NO:
+          return PairingType::DISPLAY_AND_CONFIRM;
+        case IoCapabilityType::KEYBOARD_ONLY:
+          return PairingType::DISPLAY_PIN;
+        case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+          return PairingType::AUTO_CONFIRMATION;
+        default:
+          return PairingType::INVALID;
+      }
+    case IoCapabilityType::KEYBOARD_ONLY:
+      switch (host_io_capability_) {
+        case IoCapabilityType::DISPLAY_ONLY:
+          return PairingType::DISPLAY_PIN;
+        case IoCapabilityType::DISPLAY_YES_NO:
+          return PairingType::DISPLAY_PIN;
+        case IoCapabilityType::KEYBOARD_ONLY:
+          return PairingType::INPUT_PIN;
+        case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+          return PairingType::AUTO_CONFIRMATION;
+        default:
+          return PairingType::INVALID;
+      }
+    case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+      return PairingType::AUTO_CONFIRMATION;
+    default:
+      return PairingType::INVALID;
+  }
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.h b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
index 94284cb..e77f1d1 100644
--- a/vendor_libs/test_vendor_lib/model/controller/security_manager.h
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
@@ -16,15 +16,17 @@
 
 #pragma once
 
+#include <array>
 #include <cstdint>
 #include <string>
 #include <unordered_map>
-#include <vector>
 
-#include "types/address.h"
+#include "hci/address.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 enum class PairingType : uint8_t {
   AUTO_CONFIRMATION,
   CONFIRM_Y_N,
@@ -62,12 +64,10 @@
   uint16_t DeleteKey(const Address& addr);
   uint16_t ReadAllKeys() const;
   uint16_t ReadKey(const Address& addr) const;
-  uint16_t WriteKey(const Address& addr, const std::vector<uint8_t>& key);
-  uint16_t ReadCapacity() const {
-    return max_keys_;
-  };
+  uint16_t WriteKey(const Address& addr, const std::array<uint8_t, 16>& key);
+  uint16_t ReadCapacity() const { return max_keys_; };
 
-  const std::vector<uint8_t>& GetKey(const Address& addr) const;
+  const std::array<uint8_t, 16>& GetKey(const Address& addr) const;
 
   void AuthenticationRequest(const Address& addr, uint16_t handle);
   void AuthenticationRequestFinished();
@@ -87,16 +87,16 @@
 
  private:
   uint16_t max_keys_;
-  std::unordered_map<std::string, std::vector<uint8_t>> key_store_;
+  std::unordered_map<std::string, std::array<uint8_t, 16>> key_store_;
 
   bool peer_capabilities_valid_{false};
   IoCapabilityType peer_io_capability_;
-  bool peer_oob_present_flag_;
+  bool peer_oob_present_flag_{false};
   AuthenticationType peer_authentication_requirements_;
 
   bool host_capabilities_valid_{false};
   IoCapabilityType host_io_capability_;
-  bool host_oob_present_flag_;
+  bool host_oob_present_flag_{false};
   AuthenticationType host_authentication_requirements_;
 
   bool authenticating_{false};
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.cc b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
index 10ebf5c..96f6099 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
@@ -14,31 +14,27 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "beacon"
-
 #include "beacon.h"
 
-#include "le_advertisement.h"
 #include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool Beacon::registered_ = DeviceBoutique::Register(LOG_TAG, &Beacon::Create);
+bool Beacon::registered_ = DeviceBoutique::Register("beacon", &Beacon::Create);
 
 Beacon::Beacon() {
   advertising_interval_ms_ = std::chrono::milliseconds(1280);
-  properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+  properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
   properties_.SetLeAdvertisement({0x0F,  // Length
-                                  BTM_BLE_AD_TYPE_NAME_CMPL, 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'e', 'a', 'c',
+                                  0x09 /* TYPE_NAME_CMPL */, 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'e', 'a', 'c',
                                   'o', 'n',
                                   0x02,  // Length
-                                  BTM_BLE_AD_TYPE_FLAG, BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+                                  0x01 /* TYPE_FLAG */, 0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */});
 
   properties_.SetLeScanResponse({0x05,  // Length
-                                 BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'e', 'a', 'c'});
+                                 0x08 /* TYPE_NAME_SHORT */, 'b', 'e', 'a', 'c'});
 }
 
 std::string Beacon::GetTypeString() const {
@@ -63,29 +59,35 @@
 }
 
 void Beacon::TimerTick() {
-  if (IsAdvertisementAvailable(std::chrono::milliseconds(5000))) {
-    std::unique_ptr<packets::LeAdvertisementBuilder> ad = packets::LeAdvertisementBuilder::Create(
-        LeAdvertisement::AddressType::PUBLIC,
-        static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
+  if (IsAdvertisementAvailable()) {
+    last_advertisement_ = std::chrono::steady_clock::now();
+    auto ad = model::packets::LeAdvertisementBuilder::Create(
+        properties_.GetLeAddress(), Address::kEmpty,
+        model::packets::AddressType::PUBLIC,
+        static_cast<model::packets::AdvertisementType>(
+            properties_.GetLeAdvertisementType()),
         properties_.GetLeAdvertisement());
-    std::shared_ptr<packets::LinkLayerPacketBuilder> to_send =
-        packets::LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(ad), properties_.GetLeAddress());
-    std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
-    for (std::shared_ptr<PhyLayer> phy : le_phys) {
+    std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+        std::move(ad);
+
+    for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
       phy->Send(to_send);
     }
   }
 }
 
-void Beacon::IncomingPacket(packets::LinkLayerPacketView packet) {
-  if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
-    std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
-        LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+void Beacon::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+  if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
+      packet.GetType() == model::packets::PacketType::LE_SCAN) {
+    auto scan_response = model::packets::LeScanResponseBuilder::Create(
+        properties_.GetLeAddress(), packet.GetSourceAddress(),
+        model::packets::AddressType::PUBLIC,
+        model::packets::AdvertisementType::SCAN_RESPONSE,
         properties_.GetLeScanResponse());
-    std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
-        std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
-    std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
-    for (auto phy : le_phys) {
+    std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+        std::move(scan_response);
+
+    for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
       phy->Send(to_send);
     }
   }
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.h b/vendor_libs/test_vendor_lib/model/devices/beacon.h
index faac5cc..87bb228 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon.h
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.h
@@ -20,7 +20,6 @@
 #include <vector>
 
 #include "device.h"
-#include "stack/include/btm_ble_api.h"
 
 namespace test_vendor_lib {
 
@@ -43,7 +42,8 @@
   // Set the address and advertising interval from string args.
   virtual void Initialize(const std::vector<std::string>& args) override;
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
index a065c36..c9f17f1 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "beacon_swarm"
-
 #include "beacon_swarm.h"
 
 #include "model/setup/device_boutique.h"
@@ -23,14 +21,14 @@
 using std::vector;
 
 namespace test_vendor_lib {
-bool BeaconSwarm::registered_ = DeviceBoutique::Register(LOG_TAG, &BeaconSwarm::Create);
+bool BeaconSwarm::registered_ = DeviceBoutique::Register("beacon_swarm", &BeaconSwarm::Create);
 
 BeaconSwarm::BeaconSwarm() {
   advertising_interval_ms_ = std::chrono::milliseconds(1280);
-  properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+  properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
   properties_.SetLeAdvertisement({
       0x15,  // Length
-      BTM_BLE_AD_TYPE_NAME_CMPL,
+      0x09 /* TYPE_NAME_CMPL */,
       'g',
       'D',
       'e',
@@ -52,12 +50,12 @@
       'r',
       'm',
       0x02,  // Length
-      BTM_BLE_AD_TYPE_FLAG,
-      BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+      0x01 /* TYPE_FLAG */,
+      0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */,
   });
 
   properties_.SetLeScanResponse({0x06,  // Length
-                                 BTM_BLE_AD_TYPE_NAME_SHORT, 'c', 'b', 'e', 'a', 'c'});
+                                 0x08 /* TYPE_NAME_SHORT */, 'c', 'b', 'e', 'a', 'c'});
 }
 
 void BeaconSwarm::Initialize(const vector<std::string>& args) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
index c7d6822..32c5ebb 100644
--- a/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
@@ -14,54 +14,36 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "broken_adv"
-
 #include "broken_adv.h"
 
 #include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool BrokenAdv::registered_ = DeviceBoutique::Register(LOG_TAG, &BrokenAdv::Create);
+bool BrokenAdv::registered_ = DeviceBoutique::Register("broken_adv", &BrokenAdv::Create);
 
 BrokenAdv::BrokenAdv() {
   advertising_interval_ms_ = std::chrono::milliseconds(1280);
-  properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+  properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
   constant_adv_data_ = {
-      0x02,  // Length
-      BTM_BLE_AD_TYPE_FLAG,
-      BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
-      0x13,  // Length
-      BTM_BLE_AD_TYPE_NAME_CMPL,
-      'g',
-      'D',
-      'e',
-      'v',
-      'i',
-      'c',
-      'e',
-      '-',
-      'b',
-      'r',
-      'o',
-      'k',
-      'e',
-      'n',
-      '_',
-      'a',
-      'd',
-      'v',
+      0x02,       // Length
+      0x01,       // TYPE_FLAG
+      0x4 | 0x2,  // BREDR_NOT_SPT |  GEN_DISC_FLAG
+      0x13,       // Length
+      0x09,       // TYPE_NAME_CMPL
+      'g',       'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'r', 'o', 'k', 'e', 'n', '_', 'a', 'd', 'v',
   };
   properties_.SetLeAdvertisement(constant_adv_data_);
 
   properties_.SetLeScanResponse({0x0b,  // Length
-                                 BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'});
+                                 0x08,  // TYPE_NAME_SHORT
+                                 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'});
 
   properties_.SetExtendedInquiryData({0x07,  // Length
-                                      BT_EIR_COMPLETE_LOCAL_NAME_TYPE, 'B', 'R', '0', 'K', '3', 'N'});
+                                      0x09,  // TYPE_NAME_COMPLETE
+                                      'B', 'R', '0', 'K', '3', 'N'});
   properties_.SetPageScanRepetitionMode(0);
   page_scan_delay_ms_ = std::chrono::milliseconds(600);
 }
@@ -106,7 +88,7 @@
 
   switch ((randomness & 0xf000000) >> 24) {
     case (0):
-      return BTM_EIR_MANUFACTURER_SPECIFIC_TYPE;
+      return 0xff;  // TYPE_MANUFACTURER_SPECIFIC
     case (1):
       return (randomness & 0xff);
     default:
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
index 5f7fa4a..65603f1 100644
--- a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
@@ -14,19 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "car_kit"
-
 #include "car_kit.h"
 
-#include "osi/include/log.h"
-
 #include "model/setup/device_boutique.h"
+#include "os/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool CarKit::registered_ = DeviceBoutique::Register(LOG_TAG, &CarKit::Create);
+bool CarKit::registered_ = DeviceBoutique::Register("car_kit", &CarKit::Create);
 
 CarKit::CarKit() : Device(kCarKitPropertiesFile) {
   advertising_interval_ms_ = std::chrono::milliseconds(0);
@@ -34,17 +31,20 @@
   page_scan_delay_ms_ = std::chrono::milliseconds(600);
 
   // Stub in packet handling for now
-  link_layer_controller_.RegisterAclChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
-  link_layer_controller_.RegisterEventChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
+  link_layer_controller_.RegisterAclChannel(
+      [](std::shared_ptr<bluetooth::hci::AclPacketBuilder>) {});
+  link_layer_controller_.RegisterEventChannel(
+      [](std::shared_ptr<bluetooth::hci::EventPacketBuilder>) {});
   link_layer_controller_.RegisterScoChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
   link_layer_controller_.RegisterRemoteChannel(
-      [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+      [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+             Phy::Type phy_type) {
         CarKit::SendLinkLayerPacket(packet, phy_type);
       });
 
   properties_.SetPageScanRepetitionMode(0);
   properties_.SetClassOfDevice(0x600420);
-  properties_.SetSupportedFeatures(0x8779ff9bfe8defff);
+  properties_.SetExtendedFeatures(0x8779ff9bfe8defff, 0);
   properties_.SetExtendedInquiryData({
       16,  // length
       9,   // Type: Device Name
@@ -82,7 +82,7 @@
 
   Address addr;
   if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
-  LOG_INFO(LOG_TAG, "%s SetAddress %s", ToString().c_str(), addr.ToString().c_str());
+  LOG_INFO("%s SetAddress %s", ToString().c_str(), addr.ToString().c_str());
 
   if (args.size() < 3) return;
 
@@ -93,8 +93,8 @@
   link_layer_controller_.TimerTick();
 }
 
-void CarKit::IncomingPacket(packets::LinkLayerPacketView packet) {
-  LOG_WARN(LOG_TAG, "Incoming Packet");
+void CarKit::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+  LOG_WARN("Incoming Packet");
   link_layer_controller_.IncomingPacket(packet);
 }
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.h b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
index 94057ad..f59a2ad 100644
--- a/vendor_libs/test_vendor_lib/model/devices/car_kit.h
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "device.h"
+#include "hci/hci_packets.h"
 #include "model/controller/link_layer_controller.h"
 
 namespace {
@@ -45,7 +46,8 @@
     return "car_kit";
   }
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/classic.cc b/vendor_libs/test_vendor_lib/model/devices/classic.cc
index a8f8a99..e8df43a 100644
--- a/vendor_libs/test_vendor_lib/model/devices/classic.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/classic.cc
@@ -14,28 +14,25 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "classic"
-
 #include "classic.h"
 #include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool Classic::registered_ = DeviceBoutique::Register(LOG_TAG, &Classic::Create);
+bool Classic::registered_ = DeviceBoutique::Register("classic", &Classic::Create);
 
 Classic::Classic() {
   advertising_interval_ms_ = std::chrono::milliseconds(0);
   properties_.SetClassOfDevice(0x30201);
 
-  properties_.SetExtendedInquiryData({0x10,                             // Length
-                                      BT_EIR_COMPLETE_LOCAL_NAME_TYPE,  // Type
+  properties_.SetExtendedInquiryData({0x10,  // Length
+                                      0x09,  // TYPE_NAME_CMPL
                                       'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'c', 'l', 'a', 's', 's', 'i', 'c',
                                       '\0'});  // End of data
   properties_.SetPageScanRepetitionMode(0);
-  properties_.SetSupportedFeatures(0x87593F9bFE8FFEFF);
+  properties_.SetExtendedFeatures(0x87593F9bFE8FFEFF, 0);
 
   page_scan_delay_ms_ = std::chrono::milliseconds(600);
 }
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.cc b/vendor_libs/test_vendor_lib/model/devices/device.cc
index 52a37c1..9fdcd5e 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/device.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "device"
-
 #include <vector>
 
 #include "device.h"
@@ -34,35 +32,46 @@
   phy_layers_[phy->GetType()].push_back(phy);
 }
 
-void Device::UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy) {
+void Device::UnregisterPhyLayers() {
   for (auto phy_pair : phy_layers_) {
     auto phy_list = std::get<1>(phy_pair);
-    for (size_t i = 0; i < phy_list.size(); i++) {
-      if (phy == phy_list[i]) {
-        phy_list.erase(phy_list.begin() + i);
-      }
+    for (auto phy : phy_list) {
+      phy->Unregister();
     }
   }
 }
 
-bool Device::IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const {
-  if (advertising_interval_ms_ == std::chrono::milliseconds(0)) return false;
-
-  std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
-
-  std::chrono::steady_clock::time_point last_interval =
-      ((now - time_stamp_) / advertising_interval_ms_) * advertising_interval_ms_ + time_stamp_;
-
-  std::chrono::steady_clock::time_point next_interval = last_interval + advertising_interval_ms_;
-
-  return ((now + scan_time) >= next_interval);
+void Device::UnregisterPhyLayer(Phy::Type phy_type, uint32_t factory_id) {
+  for (const auto phy_layer : phy_layers_[phy_type]) {
+    if (phy_layer->IsFactoryId(factory_id)) {
+      phy_layer->Unregister();
+      phy_layers_[phy_type].remove(phy_layer);
+    }
+  }
 }
 
-void Device::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type) {
-  auto phy_list = phy_layers_[phy_type];
-  for (auto phy : phy_list) {
+bool Device::IsAdvertisementAvailable() const {
+  return (advertising_interval_ms_ > std::chrono::milliseconds(0)) &&
+         (std::chrono::steady_clock::now() >= last_advertisement_ + advertising_interval_ms_);
+}
+
+void Device::SendLinkLayerPacket(
+    std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send,
+    Phy::Type phy_type) {
+  for (auto phy : phy_layers_[phy_type]) {
     phy->Send(to_send);
   }
 }
 
+void Device::SendLinkLayerPacket(model::packets::LinkLayerPacketView to_send,
+                                 Phy::Type phy_type) {
+  for (auto phy : phy_layers_[phy_type]) {
+    phy->Send(to_send);
+  }
+}
+
+void Device::SetAddress(Address) {
+  LOG_INFO("%s does not implement %s", GetTypeString().c_str(), __func__);
+}
+
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.h b/vendor_libs/test_vendor_lib/model/devices/device.h
index 18842cd..b985888 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/device.h
@@ -18,26 +18,27 @@
 
 #include <chrono>
 #include <cstdint>
+#include <list>
 #include <map>
 #include <string>
 #include <vector>
 
+#include "hci/address.h"
 #include "model/devices/device_properties.h"
 #include "model/setup/phy_layer.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "types/address.h"
 
-#include "stack/include/btm_ble_api.h"
+#include "packets/link_layer_packets.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 // Represent a Bluetooth Device
 //  - Provide Get*() and Set*() functions for device attributes.
 class Device {
  public:
   Device(const std::string properties_filename = "")
-      : time_stamp_(std::chrono::steady_clock::now()), properties_(properties_filename) {}
+      : last_advertisement_(std::chrono::steady_clock::now()), properties_(properties_filename) {}
   virtual ~Device() = default;
 
   // Initialize the device based on the values of |args|.
@@ -57,30 +58,38 @@
     return false;
   }
 
+  // Set the device's Bluetooth address.
+  virtual void SetAddress(Address address);
+
   // Set the advertisement interval in milliseconds.
   void SetAdvertisementInterval(std::chrono::milliseconds ms) {
     advertising_interval_ms_ = ms;
   }
 
-  // Returns true if the host could see an advertisement in the next
-  // |scan_time| milliseconds.
-  virtual bool IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const;
+  // Returns true if the host could see an advertisement about now.
+  virtual bool IsAdvertisementAvailable() const;
 
   // Let the device know that time has passed.
   virtual void TimerTick() {}
 
   void RegisterPhyLayer(std::shared_ptr<PhyLayer> phy);
 
-  void UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy);
+  void UnregisterPhyLayers();
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView){};
+  void UnregisterPhyLayer(Phy::Type phy_type, uint32_t factory_id);
 
-  virtual void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type);
+  virtual void IncomingPacket(model::packets::LinkLayerPacketView){};
+
+  virtual void SendLinkLayerPacket(
+      std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+      Phy::Type phy_type);
+  virtual void SendLinkLayerPacket(model::packets::LinkLayerPacketView packet,
+                                   Phy::Type phy_type);
 
  protected:
-  std::map<Phy::Type, std::vector<std::shared_ptr<PhyLayer>>> phy_layers_;
+  std::map<Phy::Type, std::list<std::shared_ptr<PhyLayer>>> phy_layers_;
 
-  std::chrono::steady_clock::time_point time_stamp_;
+  std::chrono::steady_clock::time_point last_advertisement_;
 
   // The time between page scans.
   std::chrono::milliseconds page_scan_delay_ms_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
index 164160a..2a4a970 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
@@ -14,19 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "device_properties"
-
 #include "device_properties.h"
 
 #include <memory>
 
-#include <base/logging.h>
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
 
 #include "hci.h"
-#include "osi/include/log.h"
+#include "os/log.h"
 #include "osi/include/osi.h"
 
 using std::vector;
@@ -48,20 +45,32 @@
 namespace test_vendor_lib {
 
 DeviceProperties::DeviceProperties(const std::string& file_name)
-    : acl_data_packet_size_(1024), sco_data_packet_size_(255), num_acl_data_packets_(10), num_sco_data_packets_(10),
-      version_(static_cast<uint8_t>(hci::Version::V4_1)), revision_(0),
-      lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)), manufacturer_name_(0), lmp_pal_subversion_(0),
-      le_data_packet_length_(27), num_le_data_packets_(15), le_white_list_size_(15) {
+    : acl_data_packet_size_(1024),
+      sco_data_packet_size_(255),
+      num_acl_data_packets_(10),
+      num_sco_data_packets_(10),
+      version_(static_cast<uint8_t>(hci::Version::V4_1)),
+      revision_(0),
+      lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)),
+      manufacturer_name_(0),
+      lmp_pal_subversion_(0),
+      le_data_packet_length_(27),
+      num_le_data_packets_(15),
+      le_white_list_size_(15),
+      le_resolving_list_size_(15) {
   std::string properties_raw;
 
-  CHECK(Address::FromString("BB:BB:BB:BB:BB:AD", address_));
-  CHECK(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
+  ASSERT(Address::FromString("BB:BB:BB:BB:BB:AD", address_));
+  ASSERT(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
   name_ = {'D', 'e', 'f', 'a', 'u', 'l', 't'};
 
   supported_codecs_ = {0};  // Only SBC is supported.
   vendor_specific_codecs_ = {};
 
-  for (int i = 0; i < 64; i++) supported_commands_.push_back(0xff);
+  for (int i = 0; i < 35; i++) supported_commands_.push_back(0xff);
+  // Mark HCI_LE_Transmitter_Test[v2] and newer commands as unsupported
+  // TODO: Implement a better mapping.
+  for (int i = 35; i < 64; i++) supported_commands_.push_back(0x00);
 
   le_supported_features_ = 0x1f;
   le_supported_states_ = 0x3ffffffffff;
@@ -70,15 +79,14 @@
   if (file_name.size() == 0) {
     return;
   }
-  LOG_INFO(LOG_TAG, "Reading controller properties from %s.", file_name.c_str());
+  LOG_INFO("Reading controller properties from %s.", file_name.c_str());
   if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
-    LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
+    LOG_ERROR("Error reading controller properties from file.");
     return;
   }
 
   std::unique_ptr<base::Value> properties_value_ptr = base::JSONReader::Read(properties_raw);
-  if (properties_value_ptr.get() == nullptr)
-    LOG_INFO(LOG_TAG, "Error controller properties may consist of ill-formed JSON.");
+  if (properties_value_ptr.get() == nullptr) LOG_INFO("Error controller properties may consist of ill-formed JSON.");
 
   // Get the underlying base::Value object, which is of type
   // base::Value::TYPE_DICTIONARY, and read it into member variables.
@@ -86,7 +94,7 @@
   base::JSONValueConverter<DeviceProperties> converter;
 
   if (!converter.Convert(properties_dictionary, this))
-    LOG_INFO(LOG_TAG, "Error converting JSON properties into Properties object.");
+    LOG_INFO("Error converting JSON properties into Properties object.");
 }
 
 // static
@@ -98,6 +106,7 @@
   converter->RegisterCustomField<uint16_t>(field_name, &DeviceProperties::field, &ParseUint16t);
   REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
   REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+  REGISTER_UINT8_T("EncryptionKeySize", encryption_key_size_);
   REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
   REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
   REGISTER_UINT8_T("Version", version_);
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.h b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
index 6960553..2cbd4b0 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device_properties.h
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
@@ -16,16 +16,21 @@
 
 #pragma once
 
+#include <array>
 #include <cstdint>
 #include <string>
 #include <vector>
 
 #include "base/json/json_value_converter.h"
-#include "types/address.h"
-#include "types/class_of_device.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "os/log.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+using ::bluetooth::hci::ClassOfDevice;
+
 class DeviceProperties {
  public:
   explicit DeviceProperties(const std::string& file_name = "");
@@ -45,8 +50,9 @@
     return extended_features_[0];
   }
 
-  void SetSupportedFeatures(uint64_t features) {
-    extended_features_[0] = features;
+  void SetExtendedFeatures(uint64_t features, uint8_t page_number) {
+    ASSERT(page_number < extended_features_.size());
+    extended_features_[page_number] = features;
   }
 
   // Specification Version 4.2, Volume 2, Part E, Section 7.4.4
@@ -55,7 +61,7 @@
   }
 
   uint64_t GetExtendedFeatures(uint8_t page_number) const {
-    CHECK(page_number < extended_features_.size());
+    ASSERT(page_number < extended_features_.size());
     return extended_features_[page_number];
   }
 
@@ -68,6 +74,8 @@
     return sco_data_packet_size_;
   }
 
+  uint8_t GetEncryptionKeySize() const { return encryption_key_size_; }
+
   uint16_t GetTotalNumAclDataPackets() const {
     return num_acl_data_packets_;
   }
@@ -138,12 +146,13 @@
   }
 
   void SetName(const std::vector<uint8_t>& name) {
-    name_ = name;
+    name_.fill(0);
+    for (size_t i = 0; i < 248 && i < name.size(); i++) {
+      name_[i] = name[i];
+    }
   }
 
-  const std::vector<uint8_t>& GetName() const {
-    return name_;
-  }
+  const std::array<uint8_t, 248>& GetName() const { return name_; }
 
   void SetExtendedInquiryData(const std::vector<uint8_t>& eid) {
     extended_inquiry_data_ = eid;
@@ -190,6 +199,47 @@
     return le_advertisement_type_;
   }
 
+  uint16_t GetLeAdvertisingIntervalMin() const {
+    return le_advertising_interval_min_;
+  }
+
+  uint16_t GetLeAdvertisingIntervalMax() const {
+    return le_advertising_interval_max_;
+  }
+
+  uint8_t GetLeAdvertisingOwnAddressType() const {
+    return le_advertising_own_address_type_;
+  }
+
+  uint8_t GetLeAdvertisingPeerAddressType() const {
+    return le_advertising_peer_address_type_;
+  }
+
+  Address GetLeAdvertisingPeerAddress() const {
+    return le_advertising_peer_address_;
+  }
+
+  uint8_t GetLeAdvertisingChannelMap() const {
+    return le_advertising_channel_map_;
+  }
+
+  uint8_t GetLeAdvertisingFilterPolicy() const {
+    return le_advertising_filter_policy_;
+  }
+
+  void SetLeAdvertisingParameters(uint16_t interval_min, uint16_t interval_max, uint8_t ad_type,
+                                  uint8_t own_address_type, uint8_t peer_address_type, Address peer_address,
+                                  uint8_t channel_map, uint8_t filter_policy) {
+    le_advertisement_type_ = ad_type;
+    le_advertising_interval_min_ = interval_min;
+    le_advertising_interval_max_ = interval_max;
+    le_advertising_own_address_type_ = own_address_type;
+    le_advertising_peer_address_type_ = peer_address_type;
+    le_advertising_peer_address_ = peer_address;
+    le_advertising_channel_map_ = channel_map;
+    le_advertising_filter_policy_ = filter_policy;
+  }
+
   void SetLeAdvertisementType(uint8_t ad_type) {
     le_advertisement_type_ = ad_type;
   }
@@ -238,6 +288,9 @@
     return le_supported_states_;
   }
 
+  // Specification Version 4.2, Volume 2, Part E, Section 7.8.41
+  uint8_t GetLeResolvingListSize() const { return le_resolving_list_size_; }
+
   // Vendor-specific commands
   const std::vector<uint8_t>& GetLeVendorCap() const {
     return le_vendor_cap_;
@@ -261,23 +314,33 @@
   std::vector<uint8_t> supported_codecs_;
   std::vector<uint32_t> vendor_specific_codecs_;
   std::vector<uint8_t> supported_commands_;
-  std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x07}};
+  std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x0f}};
   ClassOfDevice class_of_device_{{0, 0, 0}};
   std::vector<uint8_t> extended_inquiry_data_;
-  std::vector<uint8_t> name_;
+  std::array<uint8_t, 248> name_;
   Address address_;
   uint8_t page_scan_repetition_mode_;
   uint16_t clock_offset_;
+  uint8_t encryption_key_size_;
 
   // Low Energy
   uint16_t le_data_packet_length_;
   uint8_t num_le_data_packets_;
   uint8_t le_white_list_size_;
+  uint8_t le_resolving_list_size_;
   uint64_t le_supported_features_{0x075b3fd8fe8ffeff};
   uint64_t le_supported_states_;
   std::vector<uint8_t> le_vendor_cap_;
   Address le_address_;
   uint8_t le_address_type_;
+
+  uint16_t le_advertising_interval_min_;
+  uint16_t le_advertising_interval_max_;
+  uint8_t le_advertising_own_address_type_;
+  uint8_t le_advertising_peer_address_type_;
+  Address le_advertising_peer_address_;
+  uint8_t le_advertising_channel_map_;
+  uint8_t le_advertising_filter_policy_;
   uint8_t le_advertisement_type_;
   std::vector<uint8_t> le_advertisement_;
   std::vector<uint8_t> le_scan_response_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
index 3c2cde4..3591fbb 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
@@ -16,15 +16,14 @@
 
 #include "h4_packetizer.h"
 
-#define LOG_TAG "h4_packetizer"
-
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <log/log.h>
 #include <sys/uio.h>
 #include <unistd.h>
 
+#include "os/log.h"
+
 namespace test_vendor_lib {
 namespace hci {
 constexpr size_t H4Packetizer::COMMAND_PREAMBLE_SIZE;
@@ -52,15 +51,9 @@
   return (((preamble[offset + 1]) << 8) | preamble[offset]);
 }
 
-H4Packetizer::H4Packetizer(int fd, PacketReadCallback command_cb,
-                           PacketReadCallback event_cb,
-                           PacketReadCallback acl_cb, PacketReadCallback sco_cb,
-                           ClientDisconnectCallback disconnect_cb)
-    : uart_fd_(fd),
-      command_cb_(command_cb),
-      event_cb_(event_cb),
-      acl_cb_(acl_cb),
-      sco_cb_(sco_cb),
+H4Packetizer::H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb,
+                           PacketReadCallback acl_cb, PacketReadCallback sco_cb, ClientDisconnectCallback disconnect_cb)
+    : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb),
       disconnect_cb_(disconnect_cb) {}
 
 size_t H4Packetizer::Send(uint8_t type, const uint8_t* data, size_t length) {
@@ -71,16 +64,15 @@
   } while (-1 == ret && EAGAIN == errno);
 
   if (ret == -1) {
-    ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+    LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
   } else if (ret < static_cast<ssize_t>(length + 1)) {
-    ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
-          static_cast<int>(length + 1));
+    LOG_ERROR("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+              static_cast<int>(length + 1));
   }
   return ret;
 }
 
 void H4Packetizer::OnPacketReady() {
-  ALOGE("%s: before switch", __func__);
   switch (hci_packet_type_) {
     case hci::PacketType::COMMAND:
       command_cb_(packet_);
@@ -106,21 +98,18 @@
     uint8_t buffer[1] = {0};
     ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
     if (bytes_read == 0) {
-      ALOGI("%s: remote disconnected!", __func__);
+      LOG_INFO("%s: remote disconnected!", __func__);
       disconnect_cb_();
       return;
     } else if (bytes_read < 0) {
       if (errno == EAGAIN) {
         // No data, try again later.
-        ALOGV("%s: Nothing ready, will retry!", __func__);
         return;
       } else {
-        LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__,
-                         strerror(errno));
+        LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__, strerror(errno));
       }
     } else if (bytes_read > 1) {
-      LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__,
-                       static_cast<unsigned int>(bytes_read));
+      LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__, static_cast<unsigned int>(bytes_read));
     }
     hci_packet_type_ = static_cast<hci::PacketType>(buffer[0]);
     if (hci_packet_type_ != hci::PacketType::ACL && hci_packet_type_ != hci::PacketType::SCO &&
@@ -141,7 +130,7 @@
         size_t preamble_bytes = preamble_size[static_cast<size_t>(hci_packet_type_)];
         ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, preamble_ + bytes_read_, preamble_bytes - bytes_read_));
         if (bytes_read == 0) {
-          ALOGE("%s: Will try again to read the header!", __func__);
+          LOG_ERROR("%s: Will try again to read the header!", __func__);
           return;
         }
         if (bytes_read < 0) {
@@ -156,8 +145,6 @@
           size_t packet_length = HciGetPacketLengthForType(hci_packet_type_, preamble_);
           packet_.resize(preamble_bytes + packet_length);
           memcpy(packet_.data(), preamble_, preamble_bytes);
-          ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
-                static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
           bytes_remaining_ = packet_length;
           if (bytes_remaining_ == 0) {
             OnPacketReady();
@@ -176,7 +163,7 @@
         ssize_t bytes_read =
             TEMP_FAILURE_RETRY(read(fd, packet_.data() + preamble_bytes + bytes_read_, bytes_remaining_));
         if (bytes_read == 0) {
-          ALOGI("%s: Will try again to read the payload!", __func__);
+          LOG_INFO("%s: Will try again to read the payload!", __func__);
           return;
         }
         if (bytes_read < 0) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
index 4ac7f2a..c8b7917 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
@@ -30,10 +30,8 @@
 
 class H4Packetizer : public HciProtocol {
  public:
-  H4Packetizer(int fd, PacketReadCallback command_cb,
-               PacketReadCallback event_cb, PacketReadCallback acl_cb,
-               PacketReadCallback sco_cb,
-               ClientDisconnectCallback disconnect_cb);
+  H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb,
+               PacketReadCallback sco_cb, ClientDisconnectCallback disconnect_cb);
 
   size_t Send(uint8_t type, const uint8_t* data, size_t length);
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
index c4704ea..7ba432d 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
@@ -16,14 +16,13 @@
 
 #include "h4_protocol.h"
 
-#define LOG_TAG "hci-h4_protocol"
-
 #include <errno.h>
 #include <fcntl.h>
-#include <log/log.h>
 #include <sys/uio.h>
 #include <unistd.h>
 
+#include "os/log.h"
+
 namespace test_vendor_lib {
 namespace hci {
 
@@ -31,7 +30,7 @@
                        PacketReadCallback sco_cb)
     : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb),
       hci_packetizer_([this]() {
-        ALOGI("in lambda");
+        LOG_INFO("in lambda");
         this->OnPacketReady();
       }) {}
 
@@ -43,16 +42,16 @@
   } while (-1 == ret && EAGAIN == errno);
 
   if (ret == -1) {
-    ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+    LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
   } else if (ret < static_cast<ssize_t>(length + 1)) {
-    ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
-          static_cast<int>(length + 1));
+    LOG_ERROR("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+              static_cast<int>(length + 1));
   }
   return ret;
 }
 
 void H4Protocol::OnPacketReady() {
-  ALOGE("%s: before switch", __func__);
+  LOG_ERROR("%s: before switch", __func__);
   switch (hci_packet_type_) {
     case hci::PacketType::COMMAND:
       command_cb_(hci_packetizer_.GetPacket());
@@ -79,7 +78,7 @@
     ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
     if (bytes_read != 1) {
       if (bytes_read == 0) {
-        ALOGI("%s: Nothing ready, will retry!", __func__);
+        LOG_INFO("%s: Nothing ready, will retry!", __func__);
         return;
       } else if (bytes_read < 0) {
         if (errno == EAGAIN) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
index cca7780..e0c4e4a 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
@@ -16,14 +16,13 @@
 
 #include "hci_packetizer.h"
 
-#define LOG_TAG "hci_packetizer"
-
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <log/log.h>
 #include <unistd.h>
 
+#include "os/log.h"
+
 namespace test_vendor_lib {
 namespace hci {
 constexpr size_t HciPacketizer::COMMAND_PREAMBLE_SIZE;
@@ -69,7 +68,7 @@
       ssize_t bytes_read = TEMP_FAILURE_RETRY(
           read(fd, preamble_ + bytes_read_, preamble_size[static_cast<uint8_t>(packet_type)] - bytes_read_));
       if (bytes_read == 0) {
-        ALOGE("%s: Will try again to read the header!", __func__);
+        LOG_ERROR("%s: Will try again to read the header!", __func__);
         return;
       }
       if (bytes_read < 0) {
@@ -77,15 +76,15 @@
         if (errno == EAGAIN) {
           return;
         }
-        LOG_ALWAYS_FATAL("%s: Read header error: %s", __func__, strerror(errno));
+        LOG_ALWAYS_FATAL("Read header error: %s", strerror(errno));
       }
       bytes_read_ += bytes_read;
       if (bytes_read_ == preamble_size[static_cast<uint8_t>(packet_type)]) {
         size_t packet_length = HciGetPacketLengthForType(packet_type, preamble_);
         packet_.resize(preamble_size[static_cast<uint8_t>(packet_type)] + packet_length);
         memcpy(packet_.data(), preamble_, preamble_size[static_cast<uint8_t>(packet_type)]);
-        ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
-              static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
+        LOG_INFO("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
+                 static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
         bytes_remaining_ = packet_length;
         if (bytes_remaining_ == 0) {
           packet_ready_cb_();
@@ -103,7 +102,7 @@
       ssize_t bytes_read = TEMP_FAILURE_RETRY(
           read(fd, packet_.data() + preamble_size[static_cast<uint8_t>(packet_type)] + bytes_read_, bytes_remaining_));
       if (bytes_read == 0) {
-        ALOGI("%s: Will try again to read the payload!", __func__);
+        LOG_INFO("Will try again to read the payload!");
         return;
       }
       if (bytes_read < 0) {
@@ -111,7 +110,7 @@
         if (errno == EAGAIN) {
           return;
         }
-        LOG_ALWAYS_FATAL("%s: Read payload error: %s", __func__, strerror(errno));
+        LOG_ALWAYS_FATAL("Read payload error: %s", strerror(errno));
       }
       bytes_remaining_ -= bytes_read;
       bytes_read_ += bytes_read;
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
index e01bfa5..d2ef535 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
@@ -16,13 +16,13 @@
 
 #include "hci_protocol.h"
 
-#define LOG_TAG "hci-hci_protocol"
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <log/log.h>
 #include <unistd.h>
 
+#include "os/log.h"
+
 namespace test_vendor_lib {
 namespace hci {
 
@@ -33,12 +33,12 @@
 
     if (ret == -1) {
       if (errno == EAGAIN) continue;
-      ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+      LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
       break;
 
     } else if (ret == 0) {
       // Nothing written :(
-      ALOGE("%s zero bytes written - something went wrong...", __func__);
+      LOG_ERROR("%s zero bytes written - something went wrong...", __func__);
       break;
     }
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
index 04029d1..6865714 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
@@ -14,24 +14,21 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "hci_socket_device"
-
 #include "hci_socket_device.h"
 
 #include <fcntl.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
 
-#include "osi/include/log.h"
-
 #include "model/setup/device_boutique.h"
+#include "os/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
 HciSocketDevice::HciSocketDevice(int file_descriptor) : socket_file_descriptor_(file_descriptor) {
-  advertising_interval_ms_ = std::chrono::milliseconds(0);
+  advertising_interval_ms_ = std::chrono::milliseconds(1000);
 
   page_scan_delay_ms_ = std::chrono::milliseconds(600);
 
@@ -77,67 +74,53 @@
   h4_ = hci::H4Packetizer(
       socket_file_descriptor_,
       [this](const std::vector<uint8_t>& raw_command) {
-        LOG_INFO(LOG_TAG, "Rx Command");
         std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_command);
         HandleCommand(packet_copy);
       },
-      [](const std::vector<uint8_t>&) {
-        CHECK(false) << "Unexpected Event in HciSocketDevice!";
-      },
+      [](const std::vector<uint8_t>&) { LOG_ALWAYS_FATAL("Unexpected Event in HciSocketDevice!"); },
       [this](const std::vector<uint8_t>& raw_acl) {
-        LOG_INFO(LOG_TAG, "Rx ACL");
         std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_acl);
         HandleAcl(packet_copy);
       },
       [this](const std::vector<uint8_t>& raw_sco) {
-        LOG_INFO(LOG_TAG, "Rx SCO");
         std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_sco);
         HandleSco(packet_copy);
       },
       [this]() {
-        LOG_INFO(LOG_TAG, "HCI socket device disconnected");
+        LOG_INFO("HCI socket device disconnected");
         close_callback_();
       });
 
   RegisterEventChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
-    LOG_INFO(LOG_TAG, "Tx Event");
     SendHci(hci::PacketType::EVENT, packet);
   });
-  RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
-    LOG_INFO(LOG_TAG, "Tx ACL");
-    SendHci(hci::PacketType::ACL, packet);
-  });
-  RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
-    LOG_INFO(LOG_TAG, "Tx SCO");
-    SendHci(hci::PacketType::SCO, packet);
-  });
+  RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { SendHci(hci::PacketType::ACL, packet); });
+  RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { SendHci(hci::PacketType::SCO, packet); });
 }
 
 void HciSocketDevice::TimerTick() {
-  LOG_INFO(LOG_TAG, "TimerTick fd = %d", socket_file_descriptor_);
   h4_.OnDataReady(socket_file_descriptor_);
   DualModeController::TimerTick();
 }
 
 void HciSocketDevice::SendHci(hci::PacketType packet_type, const std::shared_ptr<std::vector<uint8_t>> packet) {
   if (socket_file_descriptor_ == -1) {
-    LOG_INFO(LOG_TAG, "socket_file_descriptor == -1");
+    LOG_INFO("socket_file_descriptor == -1");
     return;
   }
   uint8_t type = static_cast<uint8_t>(packet_type);
   int bytes_written;
   bytes_written = write(socket_file_descriptor_, &type, sizeof(type));
   if (bytes_written != sizeof(type)) {
-    LOG_INFO(LOG_TAG, "bytes_written %d != sizeof(type)", bytes_written);
+    LOG_WARN("bytes_written %d != sizeof(type)", bytes_written);
   }
   bytes_written = write(socket_file_descriptor_, packet->data(), packet->size());
   if (static_cast<size_t>(bytes_written) != packet->size()) {
-    LOG_INFO(LOG_TAG, "bytes_written %d != packet->size", bytes_written);
+    LOG_WARN("bytes_written %d != packet->size", bytes_written);
   }
 }
 
-void HciSocketDevice::RegisterCloseCallback(
-    std::function<void()> close_callback) {
+void HciSocketDevice::RegisterCloseCallback(std::function<void()> close_callback) {
   close_callback_ = close_callback;
 }
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
index 2cfc992..1244d3e 100644
--- a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "keyboard"
-
 #include "keyboard.h"
 
 #include "model/setup/device_boutique.h"
@@ -23,12 +21,12 @@
 using std::vector;
 
 namespace test_vendor_lib {
-bool Keyboard::registered_ = DeviceBoutique::Register(LOG_TAG, &Keyboard::Create);
+bool Keyboard::registered_ = DeviceBoutique::Register("keyboard", &Keyboard::Create);
 
 Keyboard::Keyboard() {
-  properties_.SetLeAdvertisementType(BTM_BLE_CONNECT_EVT);
+  properties_.SetLeAdvertisementType(0x00 /* CONNECTABLE */);
   properties_.SetLeAdvertisement({0x11,  // Length
-                                  BTM_BLE_AD_TYPE_NAME_CMPL,
+                                  0x09 /* TYPE_NAME_CMPL */,
                                   'g',
                                   'D',
                                   'e',
@@ -54,11 +52,11 @@
                                   0x12,
                                   0x18,
                                   0x02,  // Length
-                                  BTM_BLE_AD_TYPE_FLAG,
-                                  BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+                                  0x01 /* TYPE_FLAGS */,
+                                  0x04 /* BREDR_NOT_SPT */ | 0x02 /* GEN_DISC_FLAG */});
 
   properties_.SetLeScanResponse({0x04,  // Length
-                                 BTM_BLE_AD_TYPE_NAME_SHORT, 'k', 'e', 'y'});
+                                 0x08 /* TYPE_NAME_SHORT */, 'k', 'e', 'y'});
 }
 
 std::string Keyboard::GetTypeString() const {
@@ -82,7 +80,7 @@
   }
 }
 
-void Keyboard::IncomingPacket(packets::LinkLayerPacketView packet) {
+void Keyboard::IncomingPacket(model::packets::LinkLayerPacketView packet) {
   if (!connected_) {
     Beacon::IncomingPacket(packet);
   }
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.h b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
index 871fa52..cf00dfe 100644
--- a/vendor_libs/test_vendor_lib/model/devices/keyboard.h
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
@@ -40,7 +40,8 @@
   // Initialize the device based on the values of |args|.
   virtual void Initialize(const std::vector<std::string>& args) override;
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
index 9ccfd61..ddff51b 100644
--- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
@@ -14,17 +14,13 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "link_layer_socket_device"
-
 #include "link_layer_socket_device.h"
 
 #include <unistd.h>
 
-#include "osi/include/log.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-#include "packets/view.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+#include "packet/view.h"
 
 using std::vector;
 
@@ -35,16 +31,18 @@
 
 void LinkLayerSocketDevice::TimerTick() {
   if (bytes_left_ == 0) {
-    received_ = std::make_shared<std::vector<uint8_t>>(Link::kSizeBytes);
-    size_t bytes_received = socket_.TryReceive(Link::kSizeBytes, received_->data());
+    auto packet_size = std::make_shared<std::vector<uint8_t>>(kSizeBytes);
+
+    size_t bytes_received = socket_.TryReceive(kSizeBytes, packet_size->data());
     if (bytes_received == 0) {
       return;
     }
-    CHECK(bytes_received == Link::kSizeBytes) << "bytes_received == " << bytes_received;
-    packets::PacketView<true> size({packets::View(received_, 0, Link::kSizeBytes)});
+    ASSERT_LOG(bytes_received == kSizeBytes, "bytes_received == %d", static_cast<int>(bytes_received));
+    bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> size(
+        {bluetooth::packet::View(packet_size, 0, kSizeBytes)});
     bytes_left_ = size.begin().extract<uint32_t>();
-    received_->resize(Link::kSizeBytes + bytes_left_);
-    offset_ = Link::kSizeBytes;
+    received_ = std::make_shared<std::vector<uint8_t>>(bytes_left_);
+    offset_ = 0;
   }
   size_t bytes_received = socket_.TryReceive(bytes_left_, received_->data() + offset_);
   if (bytes_received == 0) {
@@ -53,14 +51,28 @@
   bytes_left_ -= bytes_received;
   offset_ += bytes_received;
   if (bytes_left_ == 0) {
-    SendLinkLayerPacket(packets::LinkLayerPacketBuilder::ReWrap(received_), phy_type_);
+    bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet_view(
+        received_);
+    auto packet = model::packets::LinkLayerPacketView::Create(packet_view);
+    ASSERT(packet.IsValid());
+    SendLinkLayerPacket(packet, phy_type_);
     offset_ = 0;
     received_.reset();
   }
 }
 
-void LinkLayerSocketDevice::IncomingPacket(packets::LinkLayerPacketView packet) {
-  socket_.TrySend(packet);
+void LinkLayerSocketDevice::IncomingPacket(
+    model::packets::LinkLayerPacketView packet) {
+  auto size_packet = bluetooth::packet::RawBuilder();
+  size_packet.AddOctets4(packet.size());
+  std::vector<uint8_t> size_bytes;
+  bluetooth::packet::BitInserter bit_inserter(size_bytes);
+  size_packet.Serialize(bit_inserter);
+
+  if (socket_.TrySend(size_bytes) == kSizeBytes) {
+    std::vector<uint8_t> payload_bytes{packet.begin(), packet.end()};
+    socket_.TrySend(payload_bytes);
+  }
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
index d3bbb2e..564233c 100644
--- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
@@ -20,9 +20,8 @@
 #include <vector>
 
 #include "device.h"
-#include "include/link.h"
 #include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
 #include "polled_socket.h"
 
 namespace test_vendor_lib {
@@ -43,17 +42,20 @@
 
   virtual void Initialize(const std::vector<std::string>&) override {}
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
+  static constexpr size_t kSizeBytes = sizeof(uint32_t);
+
  private:
   net::PolledSocket socket_;
   Phy::Type phy_type_;
   size_t bytes_left_{0};
   size_t offset_;
   std::shared_ptr<std::vector<uint8_t>> received_;
-  std::vector<packets::LinkLayerPacketView> packet_queue_;
+  std::vector<model::packets::LinkLayerPacketView> packet_queue_;
 };
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.cc b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
index 4d9078e..df0c762 100644
--- a/vendor_libs/test_vendor_lib/model/devices/loopback.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
@@ -14,47 +14,33 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "loopback"
-
 #include "loopback.h"
 
 #include "le_advertisement.h"
 #include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
+#include "os/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool Loopback::registered_ = DeviceBoutique::Register(LOG_TAG, &Loopback::Create);
+bool Loopback::registered_ = DeviceBoutique::Register("loopback", &Loopback::Create);
 
 Loopback::Loopback() {
   advertising_interval_ms_ = std::chrono::milliseconds(1280);
-  properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
-  properties_.SetLeAdvertisement({0x11,  // Length
-                                  BTM_BLE_AD_TYPE_NAME_CMPL,
-                                  'g',
-                                  'D',
-                                  'e',
-                                  'v',
-                                  'i',
-                                  'c',
-                                  'e',
-                                  '-',
-                                  'l',
-                                  'o',
-                                  'o',
-                                  'p',
-                                  'b',
-                                  'a',
-                                  'c',
-                                  'k',
-                                  0x02,  // Length
-                                  BTM_BLE_AD_TYPE_FLAG,
-                                  BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+  properties_.SetLeAdvertisementType(0x03);  // NON_CONNECT
+  properties_.SetLeAdvertisement({
+      0x11,  // Length
+      0x09,  // NAME_CMPL
+      'g',         'D', 'e', 'v', 'i', 'c', 'e', '-', 'l', 'o', 'o', 'p', 'b', 'a', 'c', 'k',
+      0x02,         // Length
+      0x01,         // TYPE_FLAG
+      0x04 | 0x02,  // BREDR_NOT_SPT | GEN_DISC
+  });
 
   properties_.SetLeScanResponse({0x05,  // Length
-                                 BTM_BLE_AD_TYPE_NAME_SHORT, 'l', 'o', 'o', 'p'});
+                                 0x08,  // NAME_SHORT
+                                 'l', 'o', 'o', 'p'});
 }
 
 std::string Loopback::GetTypeString() const {
@@ -80,18 +66,22 @@
 
 void Loopback::TimerTick() {}
 
-void Loopback::IncomingPacket(packets::LinkLayerPacketView packet) {
-  LOG_INFO(LOG_TAG, "Got a packet of type %d", static_cast<int>(packet.GetType()));
-  if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
-    LOG_INFO(LOG_TAG, "Got a scan");
-    std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
-        LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+void Loopback::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+  LOG_INFO("Got a packet of type %d", static_cast<int>(packet.GetType()));
+  if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
+      packet.GetType() == model::packets::PacketType::LE_SCAN) {
+    LOG_INFO("Got a scan");
+
+    auto scan_response = model::packets::LeScanResponseBuilder::Create(
+        properties_.GetLeAddress(), packet.GetSourceAddress(),
+        model::packets::AddressType::PUBLIC,
+        model::packets::AdvertisementType::SCAN_RESPONSE,
         properties_.GetLeScanResponse());
-    std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
-        std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
-    std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
-    for (auto phy : le_phys) {
-      LOG_INFO(LOG_TAG, "Sending a Scan Response on a Phy");
+    std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+        std::move(scan_response);
+
+    for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
+      LOG_INFO("Sending a Scan Response on a Phy");
       phy->Send(to_send);
     }
   }
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.h b/vendor_libs/test_vendor_lib/model/devices/loopback.h
index 31dd1cd..dd5c069 100644
--- a/vendor_libs/test_vendor_lib/model/devices/loopback.h
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.h
@@ -42,7 +42,8 @@
   // Set the address and advertising interval from string args.
   virtual void Initialize(const std::vector<std::string>& args) override;
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
index 5719132..6fea766 100644
--- a/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "polled_socket"
-
 #include "polled_socket.h"
 
-#include <base/logging.h>
 #include <fcntl.h>
 #include <netdb.h>
 #include <netinet/in.h>
@@ -26,7 +23,7 @@
 #include <sys/types.h>
 #include <sys/uio.h>
 
-#include "osi/include/log.h"
+#include "os/log.h"
 
 namespace test_vendor_lib {
 namespace net {
@@ -48,19 +45,13 @@
   file_descriptor_ = -1;
 }
 
-size_t PolledSocket::TrySend(packets::PacketView<true> packet) {
+size_t PolledSocket::TrySend(const std::vector<uint8_t>& packet) {
   if (file_descriptor_ == -1) {
     return 0;
   }
-  // Could skip this copy if the packet is guaranteed to be contiguous.
-  std::vector<uint8_t> copy;
-  copy.reserve(packet.size());
-  for (const auto&& c : packet) {
-    copy.push_back(c);
-  }
-  int ret = write(file_descriptor_, copy.data(), copy.size());
+  int ret = write(file_descriptor_, packet.data(), packet.size());
   if (ret == -1) {
-    ALOGW("%s error %s", __func__, strerror(errno));
+    LOG_WARN("%s error %s", __func__, strerror(errno));
     return 0;
   } else {
     return static_cast<size_t>(ret);
@@ -100,7 +91,7 @@
     if (errno == EAGAIN) {
       return 0;
     } else {
-      ALOGW("%s error %s", __func__, strerror(errno));
+      LOG_WARN("%s error %s", __func__, strerror(errno));
       CleanUp();
       return 0;
     }
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.h b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
index b697f56..a196fd6 100644
--- a/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
@@ -26,8 +26,6 @@
 #include <sys/socket.h>
 #include <unistd.h>
 
-#include "packets/packet_view.h"
-
 namespace test_vendor_lib {
 namespace net {
 
@@ -41,7 +39,7 @@
   PolledSocket(PolledSocket&& p);
   virtual ~PolledSocket();
 
-  size_t TrySend(packets::PacketView<true> packet);
+  size_t TrySend(const std::vector<uint8_t>& packet);
   // size_t TrySendVector(const std::vector<const std::vector<uint8_t>&>& data);
   size_t TryReceive(size_t num_bytes, uint8_t* data);
 
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
index 787e2f7..db87028 100644
--- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
@@ -14,25 +14,20 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "remote_loopback_device"
-
 #include "remote_loopback_device.h"
 
 #include "model/setup/device_boutique.h"
-
-#include "osi/include/log.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "os/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-using packets::LinkLayerPacketBuilder;
-using packets::LinkLayerPacketView;
-using packets::PageResponseBuilder;
+using model::packets::LinkLayerPacketBuilder;
+using model::packets::LinkLayerPacketView;
+using model::packets::PageResponseBuilder;
 
-bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register(LOG_TAG, &RemoteLoopbackDevice::Create);
+bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register("remote_loopback", &RemoteLoopbackDevice::Create);
 
 RemoteLoopbackDevice::RemoteLoopbackDevice() {}
 
@@ -47,27 +42,23 @@
   if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
 }
 
-void RemoteLoopbackDevice::IncomingPacket(LinkLayerPacketView packet) {
+void RemoteLoopbackDevice::IncomingPacket(
+    model::packets::LinkLayerPacketView packet) {
   // TODO: Check sender?
   // TODO: Handle other packet types
   Phy::Type phy_type = Phy::Type::BR_EDR;
 
-  Link::PacketType type = packet.GetType();
+  model::packets::PacketType type = packet.GetType();
   switch (type) {
-    case Link::PacketType::PAGE:
-      SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPageResponse(
-                              PageResponseBuilder::Create(true), packet.GetSourceAddress(), packet.GetSourceAddress()),
-                          Phy::Type::BR_EDR);
+    case model::packets::PacketType::PAGE:
+      SendLinkLayerPacket(
+          PageResponseBuilder::Create(packet.GetSourceAddress(),
+                                      packet.GetSourceAddress(), true),
+          Phy::Type::BR_EDR);
       break;
     default: {
-      ALOGW("Resend = %d", static_cast<int>(packet.size()));
-      std::shared_ptr<std::vector<uint8_t>> extracted_packet = std::make_shared<std::vector<uint8_t>>();
-      extracted_packet->reserve(packet.size());
-      for (const auto byte : packet) {
-        extracted_packet->push_back(byte);
-      }
-
-      SendLinkLayerPacket(LinkLayerPacketBuilder::ReWrap(extracted_packet), phy_type);
+      LOG_WARN("Resend = %d", static_cast<int>(packet.size()));
+      SendLinkLayerPacket(packet, phy_type);
     }
   }
 }
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
index 5513677..98c9a83 100644
--- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
@@ -20,7 +20,6 @@
 #include <vector>
 
 #include "device.h"
-#include "packets/link_layer/link_layer_packet_view.h"
 
 namespace test_vendor_lib {
 
@@ -41,7 +40,8 @@
 
   virtual void Initialize(const std::vector<std::string>& args) override;
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
  private:
   static bool registered_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
index 72008a6..b0b2165 100644
--- a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "server_port_factory"
-
 #include "server_port_factory.h"
 
-#include <base/logging.h>
-
-#include "osi/include/log.h"
+#include "os/log.h"
 #include "osi/include/osi.h"
 
 #include <netinet/in.h>
@@ -43,23 +39,23 @@
 
   OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
   if (listen_fd_ < 0) {
-    LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+    LOG_INFO("Error creating socket for test channel.");
     return -1;
   }
 
-  LOG_INFO(LOG_TAG, "port: %d", port);
+  LOG_INFO("port: %d", port);
   listen_address.sin_family = AF_INET;
   listen_address.sin_port = htons(port);
   listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
 
   if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
-    LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+    LOG_INFO("Error binding test channel listener socket to address.");
     close(listen_fd_);
     return -1;
   }
 
   if (listen(listen_fd_, 1) < 0) {
-    LOG_INFO(LOG_TAG, "Error listening for test channel.");
+    LOG_INFO("Error listening for test channel.");
     close(listen_fd_);
     return -1;
   }
@@ -71,7 +67,7 @@
     return;
   }
   if (close(listen_fd_)) {
-    LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+    LOG_ERROR("Error closing listen_fd_.");
   }
   listen_fd_ = -1;
 }
@@ -84,16 +80,16 @@
 
   OSI_NO_INTR(accept_fd = accept(listen_fd_, reinterpret_cast<sockaddr*>(&test_channel_address), &sockaddr_in_size));
   if (accept_fd < 0) {
-    LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+    LOG_INFO("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
 
     if (errno != EAGAIN && errno != EWOULDBLOCK) {
-      LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+      LOG_ERROR("Closing listen_fd_ (won't try again).");
       close(listen_fd_);
       return -1;
     }
   }
 
-  LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+  LOG_INFO("accept_fd = %d.", accept_fd);
 
   return accept_fd;
 }
@@ -107,7 +103,7 @@
   std::string command_name(command_name_raw.begin(), command_name_raw.end());
 
   if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
-    LOG_INFO(LOG_TAG, "Test channel closed");
+    LOG_INFO("Test channel closed");
     unwatch();
     close(fd);
     return;
@@ -137,9 +133,9 @@
   char size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
                       static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
   int written = write(fd, size_buf, 4);
-  CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+  ASSERT_LOG(written == 4, "What happened? written = %d errno = %d", written, errno);
   written = write(fd, response.c_str(), size);
-  CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+  ASSERT_LOG(written == static_cast<int>(size), "What happened? written = %d errno = %d", written, errno);
 }
 
 void ServerPortFactory::RegisterCommandHandler(
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
index 903ecac..efdca87 100644
--- a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
@@ -14,19 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "sniffer"
-
 #include "sniffer.h"
 
-#include "osi/include/log.h"
-
 #include "model/setup/device_boutique.h"
+#include "os/log.h"
 
 using std::vector;
 
 namespace test_vendor_lib {
 
-bool Sniffer::registered_ = DeviceBoutique::Register(LOG_TAG, &Sniffer::Create);
+bool Sniffer::registered_ = DeviceBoutique::Register("sniffer", &Sniffer::Create);
 
 Sniffer::Sniffer() {}
 
@@ -42,7 +39,7 @@
 
 void Sniffer::TimerTick() {}
 
-void Sniffer::IncomingPacket(packets::LinkLayerPacketView packet) {
+void Sniffer::IncomingPacket(model::packets::LinkLayerPacketView packet) {
   Address source = packet.GetSourceAddress();
   Address dest = packet.GetDestinationAddress();
   bool match_source = device_to_sniff_ == source;
@@ -50,8 +47,10 @@
   if (!match_source && !match_dest) {
     return;
   }
-  LOG_INFO(LOG_TAG, "%s %s -> %s (Type %d)", (match_source ? (match_dest ? "<->" : "<--") : "-->"),
-           source.ToString().c_str(), dest.ToString().c_str(), static_cast<int>(packet.GetType()));
+  LOG_INFO("%s %s -> %s (Type %s)",
+           (match_source ? (match_dest ? "<->" : "<--") : "-->"),
+           source.ToString().c_str(), dest.ToString().c_str(),
+           model::packets::PacketTypeText(packet.GetType()).c_str());
 }
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.h b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
index 3e0cfef..a5c7277 100644
--- a/vendor_libs/test_vendor_lib/model/devices/sniffer.h
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
@@ -20,11 +20,13 @@
 #include <vector>
 
 #include "device.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "types/address.h"
+#include "hci/address.h"
+#include "packets/link_layer_packets.h"
 
 namespace test_vendor_lib {
 
+using ::bluetooth::hci::Address;
+
 class Sniffer : public Device {
  public:
   Sniffer();
@@ -42,7 +44,8 @@
     return "sniffer";
   }
 
-  virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+  virtual void IncomingPacket(
+      model::packets::LinkLayerPacketView packet) override;
 
   virtual void TimerTick() override;
 
diff --git a/vendor_libs/test_vendor_lib/model/setup/async_manager.cc b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
index fb9b1ad..092271d 100644
--- a/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
@@ -14,19 +14,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "async_manager"
-
 #include "async_manager.h"
 
-#include "osi/include/log.h"
-
 #include <algorithm>
 #include <atomic>
 #include <condition_variable>
 #include <mutex>
 #include <thread>
 #include <vector>
+
 #include "fcntl.h"
+#include "os/log.h"
 #include "sys/select.h"
 #include "unistd.h"
 
@@ -105,7 +103,7 @@
     // start the thread if not started yet
     int started = tryStartThread();
     if (started != 0) {
-      LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+      LOG_ERROR("%s: Unable to start thread", __func__);
       return started;
     }
 
@@ -134,7 +132,7 @@
     if (std::this_thread::get_id() != thread_.get_id()) {
       thread_.join();
     } else {
-      LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the reading thread itself", __func__);
+      LOG_WARN("%s: Starting thread stop from inside the reading thread itself", __func__);
     }
 
     {
@@ -158,10 +156,10 @@
     // set up the communication channel
     int pipe_fds[2];
     if (pipe2(pipe_fds, O_NONBLOCK)) {
-      LOG_ERROR(LOG_TAG,
-                "%s:Unable to establish a communication channel to the reading "
-                "thread",
-                __func__);
+      LOG_ERROR(
+          "%s:Unable to establish a communication channel to the reading "
+          "thread",
+          __func__);
       return -1;
     }
     notification_listen_fd_ = pipe_fds[0];
@@ -169,7 +167,7 @@
 
     thread_ = std::thread([this]() { ThreadRoutine(); });
     if (!thread_.joinable()) {
-      LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __func__);
+      LOG_ERROR("%s: Unable to start reading thread", __func__);
       return -1;
     }
     return 0;
@@ -178,7 +176,7 @@
   int notifyThread() {
     char buffer = '0';
     if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
-      LOG_ERROR(LOG_TAG, "%s: Unable to send message to reading thread", __func__);
+      LOG_ERROR("%s: Unable to send message to reading thread", __func__);
       return -1;
     }
     return 0;
@@ -239,10 +237,10 @@
       // wait until there is data available to read on some FD
       int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL);
       if (retval <= 0) {  // there was some error or a timeout
-        LOG_ERROR(LOG_TAG,
-                  "%s: There was an error while waiting for data on the file "
-                  "descriptors: %s",
-                  __func__, strerror(errno));
+        LOG_ERROR(
+            "%s: There was an error while waiting for data on the file "
+            "descriptors: %s",
+            __func__, strerror(errno));
         continue;
       }
 
@@ -310,7 +308,7 @@
     if (std::this_thread::get_id() != thread_.get_id()) {
       thread_.join();
     } else {
-      LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the task thread itself", __func__);
+      LOG_WARN("%s: Starting thread stop from inside the task thread itself", __func__);
     }
     return 0;
   }
@@ -371,7 +369,7 @@
     // start thread if necessary
     int started = tryStartThread();
     if (started != 0) {
-      LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+      LOG_ERROR("%s: Unable to start thread", __func__);
       return kInvalidTaskId;
     }
     // notify the thread so that it knows of the new task
@@ -395,7 +393,7 @@
     running_ = true;
     thread_ = std::thread([this]() { ThreadRoutine(); });
     if (!thread_.joinable()) {
-      LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __func__);
+      LOG_ERROR("%s: Unable to start task thread", __func__);
       return -1;
     }
     return 0;
diff --git a/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
index 18de1b1..de3b1cc 100644
--- a/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "device_boutique"
-
 #include "device_boutique.h"
 
-#include "base/logging.h"
-#include "osi/include/log.h"
+#include "os/log.h"
 
 using std::vector;
 
@@ -33,16 +30,16 @@
 // Register a constructor for a device type.
 bool DeviceBoutique::Register(const std::string& device_type,
                               const std::function<std::shared_ptr<Device>()> device_constructor) {
-  LOG_INFO(LOG_TAG, "Registering %s", device_type.c_str());
+  LOG_INFO("Registering %s", device_type.c_str());
   GetMap()[device_type] = device_constructor;
   return true;
 }
 
 std::shared_ptr<Device> DeviceBoutique::Create(const vector<std::string>& args) {
-  CHECK(!args.empty());
+  ASSERT(!args.empty());
 
   if (GetMap().find(args[0]) == GetMap().end()) {
-    LOG_WARN(LOG_TAG, "No constructor registered for %s", args[0].c_str());
+    LOG_WARN("No constructor registered for %s", args[0].c_str());
     return std::shared_ptr<Device>(nullptr);
   }
 
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
index 84e4cba..7f0fa33 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
@@ -17,22 +17,33 @@
 #pragma once
 
 #include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
 
+#include "packets/link_layer_packets.h"
 namespace test_vendor_lib {
 
 class PhyLayer {
  public:
-  PhyLayer(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive)
-      : phy_type_(phy_type), id_(id), transmit_to_device_(device_receive) {}
+  PhyLayer(Phy::Type phy_type, uint32_t id,
+           const std::function<void(model::packets::LinkLayerPacketView)>&
+               device_receive,
+           uint32_t device_id)
+      : phy_type_(phy_type),
+        id_(id),
+        device_id_(device_id),
+        transmit_to_device_(device_receive) {}
 
-  virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) = 0;
+  virtual void Send(
+      const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) = 0;
+  virtual void Send(model::packets::LinkLayerPacketView packet) = 0;
 
-  virtual void Receive(packets::LinkLayerPacketView packet) = 0;
+  virtual void Receive(model::packets::LinkLayerPacketView packet) = 0;
 
   virtual void TimerTick() = 0;
 
+  virtual bool IsFactoryId(uint32_t factory_id) = 0;
+
+  virtual void Unregister() = 0;
+
   Phy::Type GetType() {
     return phy_type_;
   }
@@ -41,14 +52,18 @@
     return id_;
   }
 
+  uint32_t GetDeviceId() { return device_id_; }
+
   virtual ~PhyLayer() = default;
 
  private:
   Phy::Type phy_type_;
   uint32_t id_;
+  uint32_t device_id_;
 
  protected:
-  const std::function<void(packets::LinkLayerPacketView)> transmit_to_device_;
+  const std::function<void(model::packets::LinkLayerPacketView)>
+      transmit_to_device_;
 };
 
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
index 182416a..b963ce0 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
@@ -14,26 +14,29 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "phy_layer_factory"
-
 #include "phy_layer_factory.h"
-
-#include "base/logging.h"
-
-#include "osi/include/log.h"
+#include <sstream>
 
 namespace test_vendor_lib {
 
-PhyLayerFactory::PhyLayerFactory(Phy::Type phy_type) : phy_type_(phy_type) {}
+PhyLayerFactory::PhyLayerFactory(Phy::Type phy_type, uint32_t factory_id)
+    : phy_type_(phy_type), factory_id_(factory_id) {}
 
 Phy::Type PhyLayerFactory::GetType() {
   return phy_type_;
 }
 
+uint32_t PhyLayerFactory::GetFactoryId() {
+  return factory_id_;
+}
+
 std::shared_ptr<PhyLayer> PhyLayerFactory::GetPhyLayer(
-    const std::function<void(packets::LinkLayerPacketView)>& device_receive) {
-  std::shared_ptr<PhyLayer> new_phy =
-      std::make_shared<PhyLayerImpl>(phy_type_, next_id_++, device_receive, std::shared_ptr<PhyLayerFactory>(this));
+    const std::function<void(model::packets::LinkLayerPacketView)>&
+        device_receive,
+    uint32_t device_id) {
+  std::shared_ptr<PhyLayer> new_phy = std::make_shared<PhyLayerImpl>(
+      phy_type_, next_id_++, device_receive, device_id,
+      std::shared_ptr<PhyLayerFactory>(this));
   phy_layers_.push_back(new_phy);
   return new_phy;
 }
@@ -48,56 +51,87 @@
   }
 }
 
-void PhyLayerFactory::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id) {
+void PhyLayerFactory::Send(
+    const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+    uint32_t id) {
   // Convert from a Builder to a View
-  std::shared_ptr<std::vector<uint8_t>> serialized_packet =
-      std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
-  std::back_insert_iterator<std::vector<uint8_t>> itr(*serialized_packet);
-  serialized_packet->reserve(packet->size());
-  packet->Serialize(itr);
-  packets::LinkLayerPacketView packet_view = packets::LinkLayerPacketView::Create(serialized_packet);
+  auto bytes = std::make_shared<std::vector<uint8_t>>();
+  bluetooth::packet::BitInserter i(*bytes);
+  bytes->reserve(packet->size());
+  packet->Serialize(i);
+  auto packet_view =
+      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>(bytes);
+  auto link_layer_packet_view =
+      model::packets::LinkLayerPacketView::Create(packet_view);
+  ASSERT(link_layer_packet_view.IsValid());
 
-  for (const auto phy : phy_layers_) {
+  Send(link_layer_packet_view, id);
+}
+
+void PhyLayerFactory::Send(model::packets::LinkLayerPacketView packet,
+                           uint32_t id) {
+  for (const auto& phy : phy_layers_) {
     if (id != phy->GetId()) {
-      phy->Receive(packet_view);
+      phy->Receive(packet);
     }
   }
 }
 
 void PhyLayerFactory::TimerTick() {
-  for (auto phy : phy_layers_) {
+  for (auto& phy : phy_layers_) {
     phy->TimerTick();
   }
 }
 
 std::string PhyLayerFactory::ToString() const {
+  std::stringstream factory;
   switch (phy_type_) {
     case Phy::Type::LOW_ENERGY:
-      return "LOW_ENERGY";
+      factory << "LOW_ENERGY: ";
       break;
     case Phy::Type::BR_EDR:
-      return "BR_EDR";
+      factory << "BR_EDR: ";
       break;
     default:
-      return "Unknown";
+      factory << "Unknown: ";
   }
+  for (auto& phy : phy_layers_) {
+    factory << phy->GetDeviceId();
+    factory << ",";
+  }
+
+  return factory.str();
 }
 
-PhyLayerImpl::PhyLayerImpl(Phy::Type phy_type, uint32_t id,
-                           const std::function<void(packets::LinkLayerPacketView)>& device_receive,
-                           const std::shared_ptr<PhyLayerFactory>& factory)
-    : PhyLayer(phy_type, id, device_receive), factory_(factory) {}
+PhyLayerImpl::PhyLayerImpl(
+    Phy::Type phy_type, uint32_t id,
+    const std::function<void(model::packets::LinkLayerPacketView)>&
+        device_receive,
+    uint32_t device_id, const std::shared_ptr<PhyLayerFactory> factory)
+    : PhyLayer(phy_type, id, device_receive, device_id), factory_(factory) {}
 
 PhyLayerImpl::~PhyLayerImpl() {
-  factory_->UnregisterPhyLayer(GetId());
-  PhyLayer::~PhyLayer();
+  Unregister();
 }
 
-void PhyLayerImpl::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) {
+void PhyLayerImpl::Send(
+    const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) {
   factory_->Send(packet, GetId());
 }
 
-void PhyLayerImpl::Receive(packets::LinkLayerPacketView packet) {
+void PhyLayerImpl::Send(model::packets::LinkLayerPacketView packet) {
+  factory_->Send(packet, GetId());
+}
+
+void PhyLayerImpl::Unregister() {
+  factory_->UnregisterPhyLayer(GetId());
+}
+
+bool PhyLayerImpl::IsFactoryId(uint32_t id) {
+  return factory_->GetFactoryId() == id;
+}
+
+void PhyLayerImpl::Receive(model::packets::LinkLayerPacketView packet) {
   transmit_to_device_(packet);
 }
 
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
index 018ff78..7d46733 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
@@ -20,8 +20,7 @@
 #include <vector>
 
 #include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
 #include "phy_layer.h"
 
 namespace test_vendor_lib {
@@ -30,13 +29,18 @@
   friend class PhyLayerImpl;
 
  public:
-  PhyLayerFactory(Phy::Type phy_type);
+  PhyLayerFactory(Phy::Type phy_type, uint32_t factory_id);
 
   virtual ~PhyLayerFactory() = default;
 
   Phy::Type GetType();
 
-  std::shared_ptr<PhyLayer> GetPhyLayer(const std::function<void(packets::LinkLayerPacketView)>& device_receive);
+  uint32_t GetFactoryId();
+
+  std::shared_ptr<PhyLayer> GetPhyLayer(
+      const std::function<void(model::packets::LinkLayerPacketView)>&
+          device_receive,
+      uint32_t device_id);
 
   void UnregisterPhyLayer(uint32_t id);
 
@@ -45,23 +49,37 @@
   virtual std::string ToString() const;
 
  protected:
-  virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id);
+  virtual void Send(
+      const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+      uint32_t id);
+  virtual void Send(model::packets::LinkLayerPacketView packet, uint32_t id);
 
  private:
   Phy::Type phy_type_;
   std::vector<std::shared_ptr<PhyLayer>> phy_layers_;
   uint32_t next_id_{1};
+  const uint32_t factory_id_;
 };
 
 class PhyLayerImpl : public PhyLayer {
  public:
-  PhyLayerImpl(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive,
-               const std::shared_ptr<PhyLayerFactory>& factory);
+  PhyLayerImpl(Phy::Type phy_type, uint32_t id,
+               const std::function<void(model::packets::LinkLayerPacketView)>&
+                   device_receive,
+               uint32_t device_id,
+               const std::shared_ptr<PhyLayerFactory> factory);
   virtual ~PhyLayerImpl() override;
 
-  virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) override;
-  virtual void Receive(packets::LinkLayerPacketView packet) override;
-  virtual void TimerTick() override;
+  virtual void Send(
+      const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet)
+      override;
+  void Send(model::packets::LinkLayerPacketView packet) override;
+  void Receive(model::packets::LinkLayerPacketView packet) override;
+  void Unregister() override;
+  bool IsFactoryId(uint32_t factory_id) override;
+  void TimerTick() override;
+
+  uint32_t device_id_;
 
  private:
   std::shared_ptr<PhyLayerFactory> factory_;
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
index e89bf21..d42bc72 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
@@ -14,17 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "test_channel_transport"
-
 #include "test_channel_transport.h"
 
-#include <base/logging.h>
-
-#include "osi/include/log.h"
+#include "os/log.h"
 #include "osi/include/osi.h"
 
+#include <errno.h>
+#include <fcntl.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
+#include <unistd.h>
 
 using std::vector;
 
@@ -37,29 +36,28 @@
 
   OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
   if (listen_fd_ < 0) {
-    LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+    LOG_INFO("Error creating socket for test channel.");
     return -1;
   }
 
   int enable = 1;
-  if (setsockopt(
-      listen_fd_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
-    LOG_ERROR(LOG_TAG, "setsockopt(SO_REUSEADDR) failed");
+  if (setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
+    LOG_ERROR("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno));
   }
 
-  LOG_INFO(LOG_TAG, "port: %d", port);
+  LOG_INFO("port: %d", port);
   listen_address.sin_family = AF_INET;
   listen_address.sin_port = htons(port);
   listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
 
   if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
-    LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+    LOG_INFO("Error binding test channel listener socket to address: %s", strerror(errno));
     close(listen_fd_);
     return -1;
   }
 
   if (listen(listen_fd_, 1) < 0) {
-    LOG_INFO(LOG_TAG, "Error listening for test channel.");
+    LOG_INFO("Error listening for test channel: %s", strerror(errno));
     close(listen_fd_);
     return -1;
   }
@@ -71,7 +69,7 @@
     return;
   }
   if (close(listen_fd_)) {
-    LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+    LOG_ERROR("Error closing listen_fd_.");
   }
   listen_fd_ = -1;
 }
@@ -82,16 +80,16 @@
   OSI_NO_INTR(accept_fd = accept(listen_fd_, NULL, NULL));
 
   if (accept_fd < 0) {
-    LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+    LOG_INFO("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
 
     if (errno != EAGAIN && errno != EWOULDBLOCK) {
-      LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+      LOG_ERROR("Closing listen_fd_ (won't try again).");
       close(listen_fd_);
       return -1;
     }
   }
 
-  LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+  LOG_INFO("accept_fd = %d.", accept_fd);
 
   return accept_fd;
 }
@@ -100,18 +98,18 @@
   uint8_t command_name_size = 0;
   int bytes_read = read(fd, &command_name_size, 1);
   if (bytes_read != 1) {
-    LOG_INFO(LOG_TAG, "Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
+    LOG_INFO("Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
   }
   vector<uint8_t> command_name_raw;
   command_name_raw.resize(command_name_size);
   bytes_read = read(fd, &command_name_raw[0], command_name_size);
   if (bytes_read != command_name_size) {
-    LOG_INFO(LOG_TAG, "Unexpected (command_name) bytes_read: %d != %d", bytes_read, command_name_size);
+    LOG_INFO("Unexpected (command_name) bytes_read: %d != %d", bytes_read, command_name_size);
   }
   std::string command_name(command_name_raw.begin(), command_name_raw.end());
 
   if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
-    LOG_INFO(LOG_TAG, "Test channel closed");
+    LOG_INFO("Test channel closed");
     unwatch();
     close(fd);
     return;
@@ -120,20 +118,20 @@
   uint8_t num_args = 0;
   bytes_read = read(fd, &num_args, 1);
   if (bytes_read != 1) {
-    LOG_INFO(LOG_TAG, "Unexpected (num_args) bytes_read: %d != %d", bytes_read, 1);
+    LOG_INFO("Unexpected (num_args) bytes_read: %d != %d", bytes_read, 1);
   }
   vector<std::string> args;
   for (uint8_t i = 0; i < num_args; ++i) {
     uint8_t arg_size = 0;
     bytes_read = read(fd, &arg_size, 1);
     if (bytes_read != 1) {
-      LOG_INFO(LOG_TAG, "Unexpected (arg_size) bytes_read: %d != %d", bytes_read, 1);
+      LOG_INFO("Unexpected (arg_size) bytes_read: %d != %d", bytes_read, 1);
     }
     vector<uint8_t> arg;
     arg.resize(arg_size);
     bytes_read = read(fd, &arg[0], arg_size);
     if (bytes_read != arg_size) {
-      LOG_INFO(LOG_TAG, "Unexpected (arg) bytes_read: %d != %d", bytes_read, arg_size);
+      LOG_INFO("Unexpected (arg) bytes_read: %d != %d", bytes_read, arg_size);
     }
     args.push_back(std::string(arg.begin(), arg.end()));
   }
@@ -150,9 +148,9 @@
   uint8_t size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
                          static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
   int written = write(fd, size_buf, 4);
-  CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+  ASSERT_LOG(written == 4, "What happened? written = %d errno = %d", written, errno);
   written = write(fd, response.c_str(), size);
-  CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+  ASSERT_LOG(written == static_cast<int>(size), "What happened? written = %d errno = %d", written, errno);
 }
 
 void TestChannelTransport::RegisterCommandHandler(
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
index 108980e..a2b8b2e 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "test_command_handler"
-
 #include "test_command_handler.h"
 #include "device_boutique.h"
 #include "phy.h"
@@ -24,12 +22,11 @@
 
 #include <stdlib.h>
 
-#include <base/logging.h>
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
 
-#include "osi/include/log.h"
+#include "os/log.h"
 #include "osi/include/osi.h"
 
 using std::vector;
@@ -47,6 +44,7 @@
   SET_HANDLER("add_device_to_phy", AddDeviceToPhy);
   SET_HANDLER("del_device_from_phy", DelDeviceFromPhy);
   SET_HANDLER("list", List);
+  SET_HANDLER("set_device_address", SetDeviceAddress);
   SET_HANDLER("set_timer_period", SetTimerPeriod);
   SET_HANDLER("start_timer", StartTimer);
   SET_HANDLER("stop_timer", StopTimer);
@@ -113,11 +111,11 @@
   if (new_dev == NULL) {
     response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!";
     send_response_(response_string_);
-    LOG_WARN(LOG_TAG, "%s", response_string_.c_str());
+    LOG_WARN("%s", response_string_.c_str());
     return;
   }
 
-  LOG_INFO(LOG_TAG, "Add %s", new_dev->ToString().c_str());
+  LOG_INFO("Add %s", new_dev->ToString().c_str());
   size_t dev_index = model_.Add(new_dev);
   response_string_ = std::to_string(dev_index) + std::string(":") + new_dev->ToString();
   send_response_(response_string_);
@@ -160,11 +158,9 @@
 
 void TestCommandHandler::AddPhy(const vector<std::string>& args) {
   if (args[0] == "LOW_ENERGY") {
-    std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::LOW_ENERGY);
-    model_.AddPhy(new_phy);
+    model_.AddPhy(Phy::Type::LOW_ENERGY);
   } else if (args[0] == "BR_EDR") {
-    std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::BR_EDR);
-    model_.AddPhy(new_phy);
+    model_.AddPhy(Phy::Type::BR_EDR);
   } else {
     response_string_ = "TestCommandHandler 'add_phy' with unrecognized type " + args[0];
     send_response_(response_string_);
@@ -211,15 +207,31 @@
 
 void TestCommandHandler::List(const vector<std::string>& args) {
   if (args.size() > 0) {
-    LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+    LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
     return;
   }
   send_response_(model_.List());
 }
 
+void TestCommandHandler::SetDeviceAddress(const vector<std::string>& args) {
+  if (args.size() != 2) {
+    response_string_ = "TestCommandHandler 'set_device_address' takes two arguments";
+    send_response_(response_string_);
+    return;
+  }
+  size_t device_id = std::stoi(args[0]);
+  Address device_address;
+  Address::FromString(args[1], device_address);
+  model_.SetDeviceAddress(device_id, device_address);
+  response_string_ = "set_device_address " + args[0];
+  response_string_ += " ";
+  response_string_ += args[1];
+  send_response_(response_string_);
+}
+
 void TestCommandHandler::SetTimerPeriod(const vector<std::string>& args) {
   if (args.size() != 1) {
-    LOG_INFO(LOG_TAG, "SetTimerPeriod takes 1 argument");
+    LOG_INFO("SetTimerPeriod takes 1 argument");
   }
   size_t period = std::stoi(args[0]);
   model_.SetTimerPeriod(std::chrono::milliseconds(period));
@@ -227,14 +239,14 @@
 
 void TestCommandHandler::StartTimer(const vector<std::string>& args) {
   if (args.size() > 0) {
-    LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+    LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
   }
   model_.StartTimer();
 }
 
 void TestCommandHandler::StopTimer(const vector<std::string>& args) {
   if (args.size() > 0) {
-    LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+    LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
   }
   model_.StopTimer();
 }
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
index 409966a..4c62d84 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
@@ -69,6 +69,9 @@
   // List the devices that the test knows about
   void List(const std::vector<std::string>& args);
 
+  // Change the device's MAC address
+  void SetDeviceAddress(const std::vector<std::string>& args);
+
   // Timer management functions
   void SetTimerPeriod(const std::vector<std::string>& args);
 
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.cc b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
index ef3567f..688b7dc 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_model.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "test_model"
-
 #include "test_model.h"
 
 // TODO: Remove when registration works
@@ -30,13 +28,14 @@
 #include <memory>
 
 #include <stdlib.h>
+#include <iomanip>
+#include <iostream>
 
-#include <base/logging.h>
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/values.h"
 
-#include "osi/include/log.h"
+#include "os/log.h"
 #include "osi/include/osi.h"
 
 #include "device_boutique.h"
@@ -78,13 +77,13 @@
 }
 
 void TestModel::StartTimer() {
-  LOG_INFO(LOG_TAG, "StartTimer()");
+  LOG_INFO("StartTimer()");
   timer_tick_task_ =
       schedule_periodic_task_(std::chrono::milliseconds(0), timer_period_, [this]() { TestModel::TimerTick(); });
 }
 
 void TestModel::StopTimer() {
-  LOG_INFO(LOG_TAG, "StopTimer()");
+  LOG_INFO("StopTimer()");
   cancel_task_(timer_tick_task_);
   timer_tick_task_ = kInvalidTaskId;
 }
@@ -98,14 +97,15 @@
 void TestModel::Del(size_t dev_index) {
   auto device = devices_.find(dev_index);
   if (device == devices_.end()) {
-    LOG_WARN(LOG_TAG, "Del: can't find device!");
+    LOG_WARN("Del: can't find device!");
     return;
   }
   devices_.erase(dev_index);
 }
 
-size_t TestModel::AddPhy(std::shared_ptr<PhyLayerFactory> new_phy) {
+size_t TestModel::AddPhy(Phy::Type phy_type) {
   phys_counter_++;
+  std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(phy_type, phys_counter_);
   phys_[phys_counter_] = new_phy;
   return phys_counter_;
 }
@@ -113,7 +113,7 @@
 void TestModel::DelPhy(size_t phy_index) {
   auto phy = phys_.find(phy_index);
   if (phy == phys_.end()) {
-    LOG_WARN(LOG_TAG, "DelPhy: can't find device!");
+    LOG_WARN("DelPhy: can't find device!");
     return;
   }
   phys_.erase(phy_index);
@@ -122,32 +122,34 @@
 void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) {
   auto device = devices_.find(dev_index);
   if (device == devices_.end()) {
-    LOG_WARN(LOG_TAG, "AddDeviceToPhy: can't find device!");
+    LOG_WARN("%s: can't find device!", __func__);
     return;
   }
   auto phy = phys_.find(phy_index);
   if (phy == phys_.end()) {
-    LOG_WARN(LOG_TAG, "AddDeviceToPhy: can't find phy!");
+    LOG_WARN("%s: can't find phy!", __func__);
     return;
   }
   auto dev = device->second;
-  dev->RegisterPhyLayer(
-      phy->second->GetPhyLayer([dev](packets::LinkLayerPacketView packet) {
+  dev->RegisterPhyLayer(phy->second->GetPhyLayer(
+      [dev](model::packets::LinkLayerPacketView packet) {
         dev->IncomingPacket(packet);
-      }));
+      },
+      device->first));
 }
 
 void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) {
   auto device = devices_.find(dev_index);
   if (device == devices_.end()) {
-    LOG_WARN(LOG_TAG, "AddDeviceToPhy: can't find device!");
+    LOG_WARN("%s: can't find device!", __func__);
     return;
   }
   auto phy = phys_.find(phy_index);
   if (phy == phys_.end()) {
-    LOG_WARN(LOG_TAG, "AddDeviceToPhy: can't find phy!");
+    LOG_WARN("%s: can't find phy!", __func__);
     return;
   }
+  device->second->UnregisterPhyLayer(phy->second->GetType(), phy->second->GetFactoryId());
 }
 
 void TestModel::AddLinkLayerConnection(int socket_fd, Phy::Type phy_type) {
@@ -177,33 +179,41 @@
   auto dev = HciSocketDevice::Create(socket_fd);
   size_t index = Add(std::static_pointer_cast<Device>(dev));
   std::string addr = "da:4c:10:de:17:";  // Da HCI dev
-  CHECK(index < 256) << "Why do you need more than 256?";
   std::stringstream stream;
-  stream << std::setfill ('0') << std::setw(2) << std::hex << index;
+  stream << std::setfill('0') << std::setw(2) << std::hex << (index % 256);
   addr += stream.str();
 
   dev->Initialize({"IgnoredTypeName", addr});
-  LOG_INFO(LOG_TAG, "initialized %s", addr.c_str());
+  LOG_INFO("initialized %s", addr.c_str());
   for (auto& phy : phys_) {
     AddDeviceToPhy(index, phy.first);
   }
   dev->RegisterTaskScheduler(schedule_task_);
   dev->RegisterTaskCancel(cancel_task_);
-  dev->RegisterCloseCallback(
-      [this, socket_fd, index] { OnHciConnectionClosed(socket_fd, index); });
+  dev->RegisterCloseCallback([this, socket_fd, index] { OnHciConnectionClosed(socket_fd, index); });
 }
 
 void TestModel::OnHciConnectionClosed(int socket_fd, size_t index) {
   auto device = devices_.find(index);
   if (device == devices_.end()) {
-    LOG_WARN(LOG_TAG, "OnHciConnectionClosed: can't find device!");
+    LOG_WARN("OnHciConnectionClosed: can't find device!");
     return;
   }
   int close_result = close(socket_fd);
-  CHECK(close_result == 0) << "can't close: " << strerror(errno);
+  ASSERT_LOG(close_result == 0, "can't close: %s", strerror(errno));
+  device->second->UnregisterPhyLayers();
   devices_.erase(index);
 }
 
+void TestModel::SetDeviceAddress(size_t index, Address address) {
+  auto device = devices_.find(index);
+  if (device == devices_.end()) {
+    LOG_WARN("SetDeviceAddress can't find device!");
+    return;
+  }
+  device->second->SetAddress(address);
+}
+
 const std::string& TestModel::List() {
   list_string_ = "";
   list_string_ += " Devices: \r\n";
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.h b/vendor_libs/test_vendor_lib/model/setup/test_model.h
index a884e11..d651f50 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_model.h
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.h
@@ -47,7 +47,7 @@
   void Del(size_t device_index);
 
   // Add phy, return its index
-  size_t AddPhy(std::shared_ptr<PhyLayerFactory> phy);
+  size_t AddPhy(Phy::Type phy_type);
 
   // Remove phy by index
   void DelPhy(size_t phy_index);
@@ -69,6 +69,9 @@
   // Connect to a remote device
   void AddRemote(const std::string& server, int port, Phy::Type phy_type);
 
+  // Set the device's Bluetooth address
+  void SetDeviceAddress(size_t device_index, Address device_address);
+
   // Let devices know about the passage of time
   void TimerTick();
   void StartTimer();
diff --git a/vendor_libs/test_vendor_lib/packets/Android.bp b/vendor_libs/test_vendor_lib/packets/Android.bp
index 8a73a64..a769e14 100644
--- a/vendor_libs/test_vendor_lib/packets/Android.bp
+++ b/vendor_libs/test_vendor_lib/packets/Android.bp
@@ -14,18 +14,9 @@
         "packet_view.cc",
         "raw_builder.cc",
         "view.cc",
-        "hci/acl_packet_builder.cc",
-        "hci/acl_packet_view.cc",
         "hci/command_packet_builder.cc",
         "hci/command_packet_view.cc",
-        "hci/event_packet_builder.cc",
-        "hci/event_payload_builder.cc",
         "hci/hci_packet_builder.cc",
-        "hci/le_meta_event_builder.cc",
-        "hci/sco_packet_builder.cc",
-        "hci/sco_packet_view.cc",
-        "link_layer/link_layer_packet_builder.cc",
-        "link_layer/link_layer_packet_view.cc",
     ],
     cflags: [
         "-fvisibility=hidden",
@@ -38,6 +29,7 @@
         "system/bt/vendor_libs/test_vendor_lib/include",
         "system/bt/vendor_libs/test_vendor_lib/",
         "system/bt/",
+        "system/bt/gd",
     ],
     shared_libs: [
         "libbase",
@@ -55,11 +47,9 @@
         "clang_coverage_bin",
     ],
     srcs: [
-        "test/link_layer_packet_builder_test.cc",
         "test/packet_builder_test.cc",
         "test/packet_view_test.cc",
-        "hci/test/acl_builder_test.cc",
-        "hci/test/event_builder_test.cc",
+        ":BluetoothHciClassSources",
     ],
     header_libs: [
         "libbluetooth_headers",
@@ -69,6 +59,7 @@
     ],
     include_dirs: [
         "system/bt",
+        "system/bt/gd",
         "system/bt/hci/include",
         "system/bt/vendor_libs/test_vendor_lib",
         "system/bt/vendor_libs/test_vendor_lib/include",
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
deleted file mode 100644
index 00b0ba8..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-AclPacketBuilder::AclPacketBuilder(uint16_t handle, PacketBoundaryFlagsType packet_boundary_flags,
-                                   BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload)
-    : handle_(handle), packet_boundary_flags_(packet_boundary_flags), broadcast_flags_(broadcast_flags),
-      payload_(std::move(payload)) {}
-
-std::unique_ptr<AclPacketBuilder> AclPacketBuilder::Create(uint16_t handle,
-                                                           PacketBoundaryFlagsType packet_boundary_flags,
-                                                           BroadcastFlagsType broadcast_flags,
-                                                           std::unique_ptr<BasePacketBuilder> payload) {
-  return std::unique_ptr<AclPacketBuilder>(
-      new AclPacketBuilder(handle, packet_boundary_flags, broadcast_flags, std::move(payload)));
-}
-
-size_t AclPacketBuilder::size() const {
-  return 2 * sizeof(uint16_t) + payload_->size();
-}
-
-void AclPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
-  insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_boundary_flags_) << 12) |
-                               (static_cast<uint16_t>(broadcast_flags_) << 14)),
-         it);
-  uint16_t payload_size = payload_->size();
-
-  CHECK(static_cast<size_t>(payload_size) == payload_->size())
-      << "Payload too large for an ACL packet: " << payload_->size();
-  insert(payload_size, it);
-  payload_->Serialize(it);
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
deleted file mode 100644
index cd2a607..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2018 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 <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/acl.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class AclPacketBuilder : public HciPacketBuilder {
- public:
-  virtual ~AclPacketBuilder() override = default;
-
-  static std::unique_ptr<AclPacketBuilder> Create(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
-                                                  acl::BroadcastFlagsType broadcast_flags,
-                                                  std::unique_ptr<BasePacketBuilder> payload);
-
-  virtual size_t size() const override;
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
- private:
-  AclPacketBuilder(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
-                   acl::BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload);
-  AclPacketBuilder() = delete;
-  uint16_t handle_;
-  acl::PacketBoundaryFlagsType packet_boundary_flags_;
-  acl::BroadcastFlagsType broadcast_flags_;
-  std::unique_ptr<BasePacketBuilder> payload_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
deleted file mode 100644
index bfec835..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_view.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-AclPacketView::AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
-
-AclPacketView::AclPacketView(PacketView<true> packet_view) : PacketView<true>(packet_view) {}
-
-AclPacketView AclPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
-  return AclPacketView(packet);
-}
-
-AclPacketView AclPacketView::Create(PacketView<true> packet_view) {
-  return AclPacketView(packet_view);
-}
-
-uint16_t AclPacketView::GetHandle() const {
-  return begin().extract<uint16_t>() & 0xfff;
-}
-
-PacketBoundaryFlagsType AclPacketView::GetPacketBoundaryFlags() const {
-  return static_cast<PacketBoundaryFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
-}
-
-BroadcastFlagsType AclPacketView::GetBroadcastFlags() const {
-  return static_cast<BroadcastFlagsType>(((begin() + 1).extract<uint8_t>() & 0xc0) >> 6);
-}
-
-PacketView<true> AclPacketView::GetPayload() const {
-  uint16_t payload_size = (begin() + sizeof(uint16_t)).extract<uint16_t>();
-  CHECK(static_cast<uint16_t>(size() - 2 * sizeof(uint16_t)) == payload_size)
-      << "Malformed ACL packet payload_size " << payload_size << " + 4 != " << size();
-  return SubViewLittleEndian(2 * sizeof(uint16_t), size());
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
deleted file mode 100644
index 1e69cda..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/acl.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class AclPacketView : public PacketView<true> {
- public:
-  virtual ~AclPacketView() override = default;
-
-  static AclPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
-  static AclPacketView Create(PacketView<true> packet_view);
-
-  uint16_t GetHandle() const;
-  acl::PacketBoundaryFlagsType GetPacketBoundaryFlags() const;
-  acl::BroadcastFlagsType GetBroadcastFlags() const;
-  PacketView<true> GetPayload() const;
-
- private:
-  AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
-  AclPacketView(PacketView<true> packet_view);
-  AclPacketView() = delete;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
index 7074309..b422bb8 100644
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
@@ -16,7 +16,7 @@
 
 #include "packets/hci/command_packet_builder.h"
 
-#include <base/logging.h>
+#include "os/log.h"
 
 using std::vector;
 using test_vendor_lib::hci::OpCode;
@@ -35,8 +35,8 @@
   insert(static_cast<uint16_t>(opcode_), it);
   uint8_t payload_size = static_cast<uint8_t>(payload_->size());
 
-  CHECK(static_cast<size_t>(payload_size) == payload_->size())
-      << "Payload too large for a command packet: " << payload_->size();
+  ASSERT_LOG(static_cast<size_t>(payload_size) == payload_->size(), "Payload too large for a command packet: %d",
+             static_cast<int>(payload_->size()));
   insert(payload_size, it);
   payload_->Serialize(it);
 }
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
index d8e86a0..d59cf79 100644
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <base/logging.h>
 #include <cstdint>
 #include <memory>
 #include <vector>
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
index f0876c1..b0d27e6 100644
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
+++ b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
@@ -16,7 +16,7 @@
 
 #include "packets/hci/command_packet_view.h"
 
-#include <base/logging.h>
+#include "os/log.h"
 
 using std::vector;
 
@@ -35,8 +35,9 @@
 
 PacketView<true> CommandPacketView::GetPayload() const {
   uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
-  CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
-      << "Malformed Command packet payload_size " << payload_size << " + 2 != " << size();
+  ASSERT_LOG(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size,
+             "Malformed Command packet payload_size %d + 2 != %d", static_cast<int>(payload_size),
+             static_cast<int>(size()));
   return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
 }
 
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
deleted file mode 100644
index 8d095a7..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/event_packet_builder.h"
-
-#include <base/logging.h>
-#include "hci.h"
-#include "packets/hci/le_meta_event_builder.h"
-
-using std::vector;
-using test_vendor_lib::hci::EventCode;
-using test_vendor_lib::hci::OpCode;
-using test_vendor_lib::hci::Status;
-
-namespace test_vendor_lib {
-namespace packets {
-
-EventPacketBuilder::EventPacketBuilder(EventCode event_code)
-    : event_code_(event_code), payload_(std::make_unique<RawBuilder>()) {}
-
-EventPacketBuilder::EventPacketBuilder(EventCode event_code, std::unique_ptr<RawBuilder> payload)
-    : event_code_(event_code), payload_(std::move(payload)) {}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status status) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::INQUIRY_COMPLETE));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteEvent(
-    hci::OpCode command_opcode, const vector<uint8_t>& event_return_parameters) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-  CHECK(evt_ptr->AddPayloadOctets(event_return_parameters));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
-                                                                                             hci::Status status) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(
-    hci::OpCode command_opcode, hci::Status status, const Address& address) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadAddress(address));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(
-    uint16_t command_opcode) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(Status::UNKNOWN_COMMAND)));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandStatusEvent(hci::Status status,
-                                                                                 hci::OpCode command_opcode) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_STATUS));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // num_hci_command_packets
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(
-    uint16_t handle, uint16_t num_completed_packets) {
-  std::unique_ptr<RawBuilder> payload = std::make_unique<CountedBuilder>();
-  std::unique_ptr<EventPacketBuilder> evt_ptr = std::unique_ptr<EventPacketBuilder>(
-      new EventPacketBuilder(EventCode::NUMBER_OF_COMPLETED_PACKETS, std::move(payload)));
-
-  evt_ptr->AddCompletedPackets(handle, num_completed_packets);
-
-  return evt_ptr;
-}
-
-void EventPacketBuilder::AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets) {
-  CHECK(event_code_ == EventCode::NUMBER_OF_COMPLETED_PACKETS);
-
-  std::unique_ptr<RawBuilder> handle_pair = std::make_unique<RawBuilder>();
-  CHECK(handle_pair->AddOctets2(handle));
-  CHECK(handle_pair->AddOctets2(num_completed_packets));
-  AddBuilder(std::move(handle_pair));
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(
-    hci::Status status, uint16_t num_keys_deleted) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::DELETE_STORED_LINK_KEY, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(num_keys_deleted));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalName(
-    hci::Status status, const std::vector<uint8_t>& local_name) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
-
-  size_t len = local_name.size();
-  if (len > 247) {
-    len = 247;
-  }
-  CHECK(evt_ptr->AddPayloadOctets(len, local_name));
-  CHECK(evt_ptr->AddPayloadOctets1(0));  // Null terminated
-  for (size_t i = 0; i < 248 - len - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(
-    hci::Status status, uint8_t enable) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
-  CHECK(evt_ptr->AddPayloadOctets1(enable));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
-    hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version, uint16_t manufacturer_name,
-    uint16_t lmp_pal_subversion) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_VERSION_INFORMATION, status);
-
-  CHECK(evt_ptr->AddPayloadOctets1(hci_version));
-  CHECK(evt_ptr->AddPayloadOctets2(hci_revision));
-  CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
-  CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
-  CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
-    hci::Status status, uint16_t connection_handle, uint8_t lmp_pal_version, uint16_t manufacturer_name,
-    uint16_t lmp_pal_subversion) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(connection_handle));
-  CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
-  CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
-  CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
-
-  return evt_ptr;
-}
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(
-    hci::Status status, const vector<uint8_t>& supported_commands) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, status);
-
-  CHECK(evt_ptr->AddPayloadOctets(64, supported_commands));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
-    hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_EXTENDED_FEATURES, status);
-
-  CHECK(evt_ptr->AddPayloadOctets1(page_number));
-  CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
-  CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
-    hci::Status status, uint16_t handle, uint8_t page_number, uint8_t maximum_page_number,
-    uint64_t extended_lmp_features) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets1(page_number));
-  CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
-  CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBufferSize(
-    hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
-    uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BUFFER_SIZE, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(hc_acl_data_packet_length));
-  CHECK(evt_ptr->AddPayloadOctets1(hc_synchronous_data_packet_length));
-  CHECK(evt_ptr->AddPayloadOctets2(hc_total_num_acl_data_packets));
-  CHECK(evt_ptr->AddPayloadOctets2(hc_total_synchronous_data_packets));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status status,
-                                                                                        const Address& address) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BD_ADDR, status);
-
-  CHECK(evt_ptr->AddPayloadAddress(address));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
-    hci::Status status, const vector<uint8_t>& supported_codecs, const vector<uint32_t>& vendor_specific_codecs) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_CODECS, status);
-
-  CHECK(evt_ptr->AddPayloadOctets1(supported_codecs.size()));
-  CHECK(evt_ptr->AddPayloadOctets(supported_codecs));
-  CHECK(evt_ptr->AddPayloadOctets1(vendor_specific_codecs.size()));
-  for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
-    CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status status,
-                                                                                              hci::LoopbackMode mode) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOOPBACK_MODE, status);
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(mode)));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryResultEvent() {
-  std::unique_ptr<RawBuilder> payload = std::unique_ptr<RawBuilder>(new CountedBuilder());
-  std::unique_ptr<EventPacketBuilder> evt_ptr(new EventPacketBuilder(EventCode::INQUIRY_RESULT, std::move(payload)));
-
-  return evt_ptr;
-}
-
-bool EventPacketBuilder::AddInquiryResult(const Address& address, uint8_t page_scan_repetition_mode,
-                                          ClassOfDevice class_of_device, uint16_t clock_offset) {
-  CHECK(event_code_ == EventCode::INQUIRY_RESULT);
-
-  if (!CanAddPayloadOctets(14)) return false;
-
-  std::unique_ptr<RawBuilder> result = std::make_unique<RawBuilder>();
-
-  CHECK(result->AddAddress(address));
-  CHECK(result->AddOctets1(page_scan_repetition_mode));
-  CHECK(result->AddOctets2(0));  // Reserved
-  CHECK(result->AddOctets1(class_of_device.cod[0]));
-  CHECK(result->AddOctets1(class_of_device.cod[1]));
-  CHECK(result->AddOctets1(class_of_device.cod[2]));
-  CHECK(!(clock_offset & 0x8000));
-  CHECK(result->AddOctets2(clock_offset));
-  AddBuilder(std::move(result));
-  return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionCompleteEvent(
-    hci::Status status, uint16_t handle, const Address& address, hci::LinkType link_type, bool encryption_enabled) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK((handle & 0xf000) == 0);  // Handles are 12-bit values.
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadAddress(address));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
-  CHECK(evt_ptr->AddPayloadOctets1(encryption_enabled ? 1 : 0));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionRequestEvent(const Address& address,
-                                                                                     ClassOfDevice class_of_device,
-                                                                                     hci::LinkType link_type) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_REQUEST));
-
-  CHECK(evt_ptr->AddPayloadAddress(address));
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status status,
-                                                                                         uint16_t handle,
-                                                                                         uint8_t reason) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::DISCONNECTION_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK((handle & 0xf000) == 0);  // Handles are 12-bit values.
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets1(reason));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status status,
-                                                                                          uint16_t handle) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::AUTHENTICATION_COMPLETE));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK((handle & 0xf000) == 0);  // Handles are 12-bit values.
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(
-    hci::Status status, const Address& address, const std::string& remote_name) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_NAME_REQUEST_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadAddress(address));
-  for (size_t i = 0; i < remote_name.length(); i++) CHECK(evt_ptr->AddPayloadOctets1(remote_name[i]));
-  CHECK(evt_ptr->AddPayloadOctets1(0));  // Null terminated
-  for (size_t i = 0; i < 248 - remote_name.length() - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyRequestEvent(const Address& remote) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_REQUEST));
-  CHECK(evt_ptr->AddPayloadAddress(remote));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyNotificationEvent(const Address& remote,
-                                                                                       const std::vector<uint8_t>& key,
-                                                                                       uint8_t key_type) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_NOTIFICATION));
-  CHECK(evt_ptr->AddPayloadAddress(remote));
-  CHECK(key.size() == 16);
-  CHECK(evt_ptr->AddPayloadOctets(key));
-  CHECK(evt_ptr->AddPayloadOctets1(key_type));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLoopbackCommandEvent(hci::OpCode opcode,
-                                                                                   PacketView<true> payload) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LOOPBACK_COMMAND));
-  CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(opcode)));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(payload.size())));
-  for (const auto& payload_byte : payload)  // Fill the packet.
-    evt_ptr->AddPayloadOctets1(payload_byte);
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
-                                                                                   uint16_t offset) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_CLOCK_OFFSET_COMPLETE));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets2(offset));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status status,
-                                                                                               uint16_t handle,
-                                                                                               uint16_t packet_type) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_PACKET_TYPE_CHANGE));
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets2(packet_type));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSniffSubratingEvent(const hci::Status status,
-                                                                                  uint16_t handle) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::SNIFF_SUBRATING, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateExtendedInquiryResultEvent(
-    const Address& address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device, uint16_t clock_offset,
-    uint8_t rssi, const vector<uint8_t>& extended_inquiry_response) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::EXTENDED_INQUIRY_RESULT));
-
-  CHECK(evt_ptr->AddPayloadOctets1(1));  // Always contains a single response
-
-  CHECK(evt_ptr->AddPayloadAddress(address));
-  CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
-  CHECK(evt_ptr->AddPayloadOctets1(0));  // Reserved
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
-  CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
-  CHECK(!(clock_offset & 0x8000));
-  CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
-  CHECK(evt_ptr->AddPayloadOctets1(rssi));
-  CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response));
-  evt_ptr->AddPayloadOctets1(0x00);  // End marker
-  while (evt_ptr->AddPayloadOctets1(0x00))
-    ;  // Fill packet
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityRequestEvent(const Address& peer) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_REQUEST));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  return evt_ptr;
-}  // namespace packets
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityResponseEvent(
-    const Address& peer, uint8_t io_capability, bool oob_data_present, uint8_t authentication_requirements) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_RESPONSE));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  CHECK(evt_ptr->AddPayloadOctets1(io_capability));
-  CHECK(evt_ptr->AddPayloadOctets1(oob_data_present));
-  CHECK(evt_ptr->AddPayloadOctets1(authentication_requirements));
-  return evt_ptr;
-}  // namespace test_vendor_lib
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserConfirmationRequestEvent(const Address& peer,
-                                                                                           uint32_t numeric_value) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_CONFIRMATION_REQUEST));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  CHECK(evt_ptr->AddPayloadOctets4(numeric_value));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyRequestEvent(const Address& peer) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_REQUEST));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteOobDataRequestEvent(const Address& peer) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_OOB_DATA_REQUEST));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSimplePairingCompleteEvent(hci::Status status,
-                                                                                         const Address& peer) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::SIMPLE_PAIRING_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyNotificationEvent(const Address& peer,
-                                                                                           uint32_t passkey) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_NOTIFICATION));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  CHECK(evt_ptr->AddPayloadOctets4(passkey));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateKeypressNotificationEvent(const Address& peer,
-                                                                                        uint8_t notification_type) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::KEYPRESS_NOTIFICATION));
-
-  CHECK(evt_ptr->AddPayloadAddress(peer));
-  CHECK(evt_ptr->AddPayloadOctets1(notification_type));
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionCompleteEvent(
-    hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
-    uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
-  std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
-      status, handle, role, peer_address_type, peer, interval, latency, supervision_timeout);
-
-  return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
-    hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
-    const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
-    uint16_t supervision_timeout) {
-  std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
-      status, handle, role, peer_address_type, peer, local_private_address, peer_private_address, interval, latency,
-      supervision_timeout);
-
-  return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(
-    hci::Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
-  std::unique_ptr<RawBuilder> meta_evt =
-      LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(status, handle, interval, latency, supervision_timeout);
-
-  return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeAdvertisingReportEvent() {
-  std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeAdvertisingReportEvent();
-
-  return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-bool EventPacketBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
-                                                LeAdvertisement::AddressType addr_type, const Address& addr,
-                                                const vector<uint8_t>& data, uint8_t rssi) {
-  CHECK(event_code_ == EventCode::LE_META_EVENT);
-
-  // Upcast the payload to add the next report.
-  LeMetaEventBuilder* meta_ptr = static_cast<LeMetaEventBuilder*>(payload_.get());
-  return meta_ptr->AddLeAdvertisingReport(event_type, addr_type, addr, data, rssi);
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(hci::Status status,
-                                                                                        uint16_t handle,
-                                                                                        uint64_t features) {
-  std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(status, handle, features);
-  return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(hci::Status status,
-                                                                                           uint16_t handle,
-                                                                                           uint64_t features) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets8(features));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
-                                                                                                 Address address) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_REPLY, status);
-
-  CHECK(evt_ptr->AddPayloadAddress(address));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(
-    hci::Status status, Address address) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, status);
-
-  CHECK(evt_ptr->AddPayloadAddress(address));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
-                                                                                                     uint16_t handle) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_POLICY_SETTINGS, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(
-    hci::Status status, uint16_t handle) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
-    hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_BUFFER_SIZE, status);
-
-  CHECK(evt_ptr->AddPayloadOctets2(hc_le_data_packet_length));
-  CHECK(evt_ptr->AddPayloadOctets1(hc_total_num_le_data_packets));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
-    hci::Status status, uint64_t le_features) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, status);
-
-  CHECK(evt_ptr->AddPayloadOctets8(le_features));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(
-    hci::Status status, uint8_t white_list_size) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_WHITE_LIST_SIZE, status);
-
-  CHECK(evt_ptr->AddPayloadOctets8(white_list_size));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status status,
-                                                                                    uint64_t random_val) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_RAND, status);
-
-  CHECK(evt_ptr->AddPayloadOctets8(random_val));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status status,
-                                                                                                   uint64_t le_states) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_SUPPORTED_STATES, status);
-
-  CHECK(evt_ptr->AddPayloadOctets8(le_states));
-
-  return evt_ptr;
-}
-
-// Vendor-specific commands
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(
-    hci::Status status, const vector<uint8_t>& vendor_cap) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_GET_VENDOR_CAPABILITIES, status);
-
-  CHECK(evt_ptr->AddPayloadOctets(vendor_cap));
-
-  return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateEncryptionChange(hci::Status status, uint16_t handle,
-                                                                               uint8_t encryption_enable) {
-  std::unique_ptr<EventPacketBuilder> evt_ptr =
-      std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::ENCRYPTION_CHANGE));
-
-  CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddPayloadOctets2(handle));
-  CHECK(evt_ptr->AddPayloadOctets1(encryption_enable));
-
-  return evt_ptr;
-}
-
-size_t EventPacketBuilder::size() const {
-  size_t header_size = 2;  // Event code and payload size
-  return header_size + payload_->size();
-}
-
-void EventPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
-  insert(static_cast<uint8_t>(event_code_), it);
-  uint8_t payload_size = size() - 2;  // Event code and payload size
-  CHECK(size() - 2 == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
-  insert(payload_size, it);
-  payload_->Serialize(it);
-}
-
-bool EventPacketBuilder::CanAddPayloadOctets(size_t octets) {
-  return payload_->CanAddOctets(octets);
-}
-
-bool EventPacketBuilder::AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes) {
-  return payload_->AddOctets(octets, bytes);
-}
-
-bool EventPacketBuilder::AddPayloadOctets(const std::vector<uint8_t>& bytes) {
-  return payload_->AddOctets(bytes);
-}
-
-bool EventPacketBuilder::AddPayloadOctets1(uint8_t value) {
-  return payload_->AddOctets1(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets2(uint16_t value) {
-  return payload_->AddOctets2(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets3(uint32_t value) {
-  return payload_->AddOctets3(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets4(uint32_t value) {
-  return payload_->AddOctets4(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets6(uint64_t value) {
-  return payload_->AddOctets6(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets8(uint64_t value) {
-  return payload_->AddOctets8(value);
-}
-
-bool EventPacketBuilder::AddPayloadAddress(Address address) {
-  return payload_->AddAddress(address);
-}
-
-bool EventPacketBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
-  // Upcast the payload to add the next builder.
-  CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
-  temp_ptr->Add(std::move(builder));
-  return true;
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
deleted file mode 100644
index 495e47a..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2018 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 <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "include/hci.h"
-#include "include/le_advertisement.h"
-#include "packets/counted_builder.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-#include "packets/raw_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Event Packets are specified in the Bluetooth Core Specification Version 4.2,
-// Volume 2, Part E, Section 5.4.4 (page 477). Event Packets begin with a 2
-// octet header formatted as follows:
-// - Event Code: 1 octet
-// - Parameter Total Length: 1 octet
-class EventPacketBuilder : public HciPacketBuilder {
- public:
-  virtual ~EventPacketBuilder() override = default;
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
-  static std::unique_ptr<EventPacketBuilder> CreateInquiryCompleteEvent(hci::Status status);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
-  // This should only be used for testing to send non-standard packets
-  // Most code should use the more specific functions that follow
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteEvent(
-      hci::OpCode command_opcode, const std::vector<uint8_t>& event_return_parameters);
-
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
-                                                                                  hci::Status status);
-
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteStatusAndAddressEvent(hci::OpCode command_opcode,
-                                                                                        hci::Status status,
-                                                                                        const Address& address);
-
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
-  static std::unique_ptr<EventPacketBuilder> CreateCommandStatusEvent(hci::Status status, hci::OpCode command_opcode);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
-  static std::unique_ptr<EventPacketBuilder> CreateNumberOfCompletedPacketsEvent(uint16_t handle,
-                                                                                 uint16_t num_completed_packets);
-
-  void AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.10
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
-                                                                                      Address address);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.11
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestNegativeReply(hci::Status status,
-                                                                                              Address address);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.2.10
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
-                                                                                          uint16_t handle);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteDeleteStoredLinkKey(hci::Status status,
-                                                                                      uint16_t num_keys_deleted);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalName(hci::Status status,
-                                                                                const std::vector<uint8_t>& local_name);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadAuthenticationEnable(hci::Status status,
-                                                                                           uint8_t enable);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.42
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkSupervisionTimeout(hci::Status status,
-                                                                                              uint16_t handle);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalVersionInformation(
-      hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version,
-      uint16_t manufacturer_name, uint16_t lmp_pal_subversion);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCommands(
-      hci::Status status, const std::vector<uint8_t>& supported_commands);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalExtendedFeatures(
-      hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBufferSize(
-      hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
-      uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBdAddr(hci::Status status,
-                                                                             const Address& bt_address);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCodecs(
-      hci::Status status, const std::vector<uint8_t>& supported_codecs,
-      const std::vector<uint32_t>& vendor_specific_codecs);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLoopbackMode(hci::Status status,
-                                                                                   hci::LoopbackMode mode);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
-  static std::unique_ptr<EventPacketBuilder> CreateInquiryResultEvent();
-
-  // Returns true if the result can be added to the event packet.
-  bool AddInquiryResult(const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
-                        uint16_t clock_offset);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
-  static std::unique_ptr<EventPacketBuilder> CreateConnectionCompleteEvent(hci::Status status, uint16_t handle,
-                                                                           const Address& address,
-                                                                           hci::LinkType link_type,
-                                                                           bool encryption_enabled);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
-  static std::unique_ptr<EventPacketBuilder> CreateConnectionRequestEvent(const Address& address,
-                                                                          ClassOfDevice class_of_device,
-                                                                          hci::LinkType link_type);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
-  static std::unique_ptr<EventPacketBuilder> CreateDisconnectionCompleteEvent(hci::Status status, uint16_t handle,
-                                                                              uint8_t reason);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
-  static std::unique_ptr<EventPacketBuilder> CreateAuthenticationCompleteEvent(hci::Status status, uint16_t handle);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
-  static std::unique_ptr<EventPacketBuilder> CreateRemoteNameRequestCompleteEvent(hci::Status status,
-                                                                                  const Address& bt_address,
-                                                                                  const std::string& name);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.11
-  static std::unique_ptr<EventPacketBuilder> CreateRemoteSupportedFeaturesEvent(hci::Status status, uint16_t handle,
-                                                                                uint64_t features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.12
-  static std::unique_ptr<EventPacketBuilder> CreateReadRemoteVersionInformationEvent(hci::Status status,
-                                                                                     uint16_t connection_handle,
-                                                                                     uint8_t lmp_pal_version,
-                                                                                     uint16_t manufacturer_name,
-                                                                                     uint16_t lmp_pal_subversion);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
-  static std::unique_ptr<EventPacketBuilder> CreateLinkKeyRequestEvent(const Address& remote);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
-  static std::unique_ptr<EventPacketBuilder> CreateLinkKeyNotificationEvent(const Address& remote,
-                                                                            const std::vector<uint8_t>& key,
-                                                                            uint8_t key_type);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
-  static std::unique_ptr<EventPacketBuilder> CreateLoopbackCommandEvent(hci::OpCode opcode, PacketView<true> payload);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
-  static std::unique_ptr<EventPacketBuilder> CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
-                                                                        uint16_t packet_type);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
-  static std::unique_ptr<EventPacketBuilder> CreateConnectionPacketTypeChangedEvent(hci::Status status, uint16_t handle,
-                                                                                    uint16_t offset);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.34
-  static std::unique_ptr<EventPacketBuilder> CreateReadRemoteExtendedFeaturesEvent(hci::Status status, uint16_t handle,
-                                                                                   uint8_t page_number,
-                                                                                   uint8_t maximum_page_number,
-                                                                                   uint64_t extended_lmp_features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
-  static std::unique_ptr<EventPacketBuilder> CreateSniffSubratingEvent(hci::Status status, uint16_t handle);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
-  static std::unique_ptr<EventPacketBuilder> CreateExtendedInquiryResultEvent(
-      const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
-      uint16_t clock_offset, uint8_t rssi, const std::vector<uint8_t>& extended_inquiry_response);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
-  static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityRequestEvent(const Address& peer);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
-  static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityResponseEvent(const Address& peer, uint8_t io_capability,
-                                                                             bool oob_data_present,
-                                                                             uint8_t authentication_requirements);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
-  static std::unique_ptr<EventPacketBuilder> CreateUserConfirmationRequestEvent(const Address& peer,
-                                                                                uint32_t numeric_value);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
-  static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyRequestEvent(const Address& peer);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
-  static std::unique_ptr<EventPacketBuilder> CreateRemoteOobDataRequestEvent(const Address& peer);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
-  static std::unique_ptr<EventPacketBuilder> CreateSimplePairingCompleteEvent(hci::Status status, const Address& peer);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
-  static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyNotificationEvent(const Address& peer, uint32_t passkey);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
-  static std::unique_ptr<EventPacketBuilder> CreateKeypressNotificationEvent(const Address& peer,
-                                                                             uint8_t notification_type);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.1
-  static std::unique_ptr<EventPacketBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
-                                                                             uint8_t role, uint8_t peer_address_type,
-                                                                             const Address& peer, uint16_t interval,
-                                                                             uint16_t latency,
-                                                                             uint16_t supervision_timeout);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.2
-  static std::unique_ptr<EventPacketBuilder> CreateLeAdvertisingReportEvent();
-
-  // Returns true if the report can be added to the event packet.
-  bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
-                              const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.3
-  static std::unique_ptr<EventPacketBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
-                                                                                   uint16_t interval, uint16_t latency,
-                                                                                   uint16_t supervision_timeout);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.4
-  static std::unique_ptr<EventPacketBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
-                                                                             uint64_t features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.10
-  static std::unique_ptr<EventPacketBuilder> CreateLeEnhancedConnectionCompleteEvent(
-      hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
-      const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
-      uint16_t supervision_timeout);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadBufferSize(
-      hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadLocalSupportedFeatures(hci::Status status,
-                                                                                               uint64_t le_features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadWhiteListSize(hci::Status status,
-                                                                                      uint8_t white_list_size);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeRand(hci::Status status, uint64_t random_val);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadSupportedStates(hci::Status status,
-                                                                                        uint64_t le_states);
-
-  /*
-  static std::unique_ptr<EventPacketBuilder>
-      CreateLeStartEncryption(hci::Status status, uint8_t encryption_enable);
-*/
-  static std::unique_ptr<EventPacketBuilder> CreateEncryptionChange(hci::Status status, uint16_t handle,
-                                                                    uint8_t encryption_enable);
-
-  // Vendor-specific commands
-
-  static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeGetVendorCapabilities(
-      hci::Status status, const std::vector<uint8_t>& vendor_cap);
-
-  virtual size_t size() const override;
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
-  bool CanAddPayloadOctets(size_t octets);
-
-  bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
-  bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
-
-  bool AddPayloadOctets1(uint8_t value);
-  bool AddPayloadOctets2(uint16_t value);
-  bool AddPayloadOctets3(uint32_t value);
-  bool AddPayloadOctets4(uint32_t value);
-  bool AddPayloadOctets6(uint64_t value);
-  bool AddPayloadOctets8(uint64_t value);
-
-  bool AddPayloadAddress(Address address);
-
-  bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
-
- private:
-  explicit EventPacketBuilder(hci::EventCode event_code);
-  explicit EventPacketBuilder(hci::EventCode event_code, std::unique_ptr<RawBuilder> payload);
-  hci::EventCode event_code_;
-  std::unique_ptr<RawBuilder> payload_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
deleted file mode 100644
index dd866a2..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2018 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 "event_payload_builder.h"
-
-#include <base/logging.h>
-#include <algorithm>
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-EventPayloadBuilder::EventPayloadBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
-
-bool EventPayloadBuilder::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
-  if (payload_.size() + octets > max_bytes_) return false;
-
-  if (octets != bytes.size()) return false;
-
-  payload_.insert(payload_.end(), bytes.begin(), bytes.end());
-
-  return true;
-}
-
-bool EventPayloadBuilder::AddPayloadOctets(const vector<uint8_t>& bytes) {
-  return AddPayloadOctets(bytes.size(), bytes);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets(size_t octets, uint64_t value) {
-  vector<uint8_t> val_vector;
-
-  uint64_t v = value;
-
-  if (octets > sizeof(uint64_t)) return false;
-
-  for (size_t i = 0; i < octets; i++) {
-    val_vector.push_back(v & 0xff);
-    v = v >> 8;
-  }
-
-  if (v != 0) return false;
-
-  return AddPayloadOctets(octets, val_vector);
-}
-
-bool EventPayloadBuilder::AddPayloadAddress(const Address& address) {
-  if (payload_.size() + Address::kLength > max_bytes_) return false;
-
-  for (size_t i = 0; i < Address::kLength; i++) {
-    payload_.push_back(address.address[i]);
-  }
-  return true;
-}
-
-bool EventPayloadBuilder::AddPayloadOctets1(uint8_t value) {
-  return AddPayloadOctets(1, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets2(uint16_t value) {
-  return AddPayloadOctets(2, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets3(uint32_t value) {
-  return AddPayloadOctets(3, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets4(uint32_t value) {
-  return AddPayloadOctets(4, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets6(uint64_t value) {
-  return AddPayloadOctets(6, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets8(uint64_t value) {
-  return AddPayloadOctets(8, value);
-}
-
-bool EventPayloadBuilder::CanAddPayloadOctets(size_t num_bytes) const {
-  return payload_.size() + num_bytes <= max_bytes_;
-}
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
deleted file mode 100644
index b656edf..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <vector>
-
-#include "packets/packet_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EventPayloadBuilder : public PacketBuilder<true> {
- public:
-  EventPayloadBuilder() = default;
-  EventPayloadBuilder(size_t max_bytes);
-  virtual ~EventPayloadBuilder() = default;
-
-  virtual size_t size() const override;
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
-  // Add |octets| bytes to the payload.  Return true if:
-  // - the size of |bytes| is equal to |octets| and
-  // - the new size of the payload is still < |max_bytes_|
-  bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
-  bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
-
-  bool AddPayloadOctets1(uint8_t value);
-  bool AddPayloadOctets2(uint16_t value);
-  bool AddPayloadOctets3(uint32_t value);
-  bool AddPayloadOctets4(uint32_t value);
-  bool AddPayloadOctets6(uint64_t value);
-  bool AddPayloadOctets8(uint64_t value);
-
- private:
-  // Add |octets| bytes to the payload.  Return true if:
-  // - the value of |value| fits in |octets| bytes and
-  // - the new size of the payload is still < |max_bytes_|
-  bool AddPayloadOctets(size_t octets, uint64_t value);
-
-  // Add |address| to the payload.  Return true if:
-  // - the new size of the payload is still < |max_bytes_|
-  bool AddPayloadAddress(const Address& address);
-
-  // Return true if |num_bytes| can be added to the payload.
-  bool CanAddPayloadOctets(size_t num_bytes) const;
-
-  size_t max_bytes_{255};
-
-  // Underlying containers for storing the actual packet
-  std::vector<uint8_t> payload_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
deleted file mode 100644
index f0599a7..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/le_meta_event_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::hci::LeSubEventCode;
-using test_vendor_lib::hci::Status;
-
-namespace test_vendor_lib {
-namespace packets {
-
-LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code)
-    : sub_event_code_(sub_event_code), payload_(std::make_unique<RawBuilder>()) {}
-
-LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload)
-    : sub_event_code_(sub_event_code), payload_(std::move(payload)) {}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
-    Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer, uint16_t interval,
-    uint16_t latency, uint16_t supervision_timeout) {
-  std::unique_ptr<LeMetaEventBuilder> evt_ptr =
-      std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_COMPLETE));
-
-  CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddOctets2(handle));
-  CHECK(evt_ptr->AddOctets1(role));
-  CHECK(evt_ptr->AddOctets1(peer_address_type));
-  CHECK(evt_ptr->AddAddress(peer));
-  CHECK(evt_ptr->AddOctets2(interval));
-  CHECK(evt_ptr->AddOctets2(latency));
-  CHECK(evt_ptr->AddOctets2(supervision_timeout));
-  CHECK(evt_ptr->AddOctets1(0x00));  // Master Clock Accuracy (unused for master)
-
-  return evt_ptr;
-}
-
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
-    Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
-    const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
-    uint16_t supervision_timeout) {
-  std::unique_ptr<LeMetaEventBuilder> evt_ptr =
-      std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::ENHANCED_CONNECTION_COMPLETE));
-
-  CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddOctets2(handle));
-  CHECK(evt_ptr->AddOctets1(role));
-  CHECK(evt_ptr->AddOctets1(peer_address_type));
-  CHECK(evt_ptr->AddAddress(peer));
-  CHECK(evt_ptr->AddAddress(local_private_address));
-  CHECK(evt_ptr->AddAddress(peer_private_address));
-  CHECK(evt_ptr->AddOctets2(interval));
-  CHECK(evt_ptr->AddOctets2(latency));
-  CHECK(evt_ptr->AddOctets2(supervision_timeout));
-  CHECK(evt_ptr->AddOctets1(0x00));  // Master Clock Accuracy (unused for master)
-
-  return evt_ptr;
-}
-
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(
-    Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
-  std::unique_ptr<LeMetaEventBuilder> evt_ptr =
-      std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_UPDATE_COMPLETE));
-
-  CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddOctets2(handle));
-  CHECK(evt_ptr->AddOctets2(interval));
-  CHECK(evt_ptr->AddOctets2(latency));
-  CHECK(evt_ptr->AddOctets2(supervision_timeout));
-
-  return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeAdvertisingReportEvent() {
-  std::unique_ptr<LeMetaEventBuilder> evt_ptr = std::unique_ptr<LeMetaEventBuilder>(
-      new LeMetaEventBuilder(LeSubEventCode::ADVERTISING_REPORT, std::unique_ptr<RawBuilder>(new CountedBuilder())));
-
-  return evt_ptr;
-}
-
-bool LeMetaEventBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
-                                                LeAdvertisement::AddressType addr_type, const Address& addr,
-                                                const vector<uint8_t>& data, uint8_t rssi) {
-  if (!CanAddOctets(10 + data.size())) return false;
-
-  CHECK(sub_event_code_ == LeSubEventCode::ADVERTISING_REPORT);
-
-  std::unique_ptr<RawBuilder> ad = std::make_unique<RawBuilder>();
-
-  CHECK(ad->AddOctets1(static_cast<uint8_t>(event_type)));
-  CHECK(ad->AddOctets1(static_cast<uint8_t>(addr_type)));
-  CHECK(ad->AddAddress(addr));
-  CHECK(ad->AddOctets1(data.size()));
-  CHECK(ad->AddOctets(data));
-  CHECK(ad->AddOctets1(rssi));
-  AddBuilder(std::move(ad));
-  return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(Status status, uint16_t handle,
-                                                                                        uint64_t features) {
-  std::unique_ptr<LeMetaEventBuilder> evt_ptr =
-      std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::READ_REMOTE_FEATURES_COMPLETE));
-
-  CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
-  CHECK(evt_ptr->AddOctets2(handle));
-  CHECK(evt_ptr->AddOctets8(features));
-
-  return evt_ptr;
-}
-
-size_t LeMetaEventBuilder::size() const {
-  return 1 + payload_->size();  // Add the sub_event_code
-}
-
-void LeMetaEventBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
-  insert(static_cast<uint8_t>(sub_event_code_), it);
-  uint8_t payload_size = size() - sizeof(uint8_t);
-  CHECK(size() - sizeof(uint8_t) == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
-  payload_->Serialize(it);
-}
-
-bool LeMetaEventBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
-  // Upcast the payload to add the next builder.
-  CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
-  temp_ptr->Add(std::move(builder));
-  return true;
-}
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
deleted file mode 100644
index b1d713d..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2018 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 <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "include/hci.h"
-#include "include/le_advertisement.h"
-#include "packets/counted_builder.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-#include "packets/raw_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// LE Meta Event Packets are specified in the Bluetooth Core Specification
-// Version 4.2, Volume 2, Part E, Section 7.7.65. The first byte is the
-// Subevent_Code.
-class LeMetaEventBuilder : public RawBuilder {
- public:
-  virtual ~LeMetaEventBuilder() override = default;
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.1
-  static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
-                                                                             uint8_t role, uint8_t peer_address_type,
-                                                                             const Address& peer, uint16_t interval,
-                                                                             uint16_t latency,
-                                                                             uint16_t supervision_timeout);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.2
-  static std::unique_ptr<LeMetaEventBuilder> CreateLeAdvertisingReportEvent();
-
-  // Returns true if the report can be added to the event packet.
-  bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
-                              const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.3
-  static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
-                                                                                   uint16_t interval, uint16_t latency,
-                                                                                   uint16_t supervision_timeout);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.4
-  static std::unique_ptr<LeMetaEventBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
-                                                                             uint64_t features);
-
-  // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
-  // 7.7.65.10
-  static std::unique_ptr<LeMetaEventBuilder> CreateLeEnhancedConnectionCompleteEvent(
-      hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
-      const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
-      uint16_t supervision_timeout);
-
-  virtual size_t size() const override;
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
-  bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
-
- private:
-  explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code);
-  explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload);
-  hci::LeSubEventCode sub_event_code_;
-  std::unique_ptr<RawBuilder> payload_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
deleted file mode 100644
index 57203ed..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/sco_packet_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::sco::PacketStatusFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-ScoPacketBuilder::ScoPacketBuilder(uint16_t handle, PacketStatusFlagsType packet_status_flags,
-                                   std::unique_ptr<BasePacketBuilder> payload)
-    : handle_(handle), packet_status_flags_(packet_status_flags), payload_(std::move(payload)) {}
-
-size_t ScoPacketBuilder::size() const {
-  return 2 * sizeof(uint16_t) + payload_->size();
-}
-
-void ScoPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
-  insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_status_flags_) << 12)), it);
-  uint8_t payload_size = payload_->size();
-
-  CHECK(static_cast<size_t>(payload_size) == payload_->size())
-      << "Payload too large for a SCO packet: " << payload_->size();
-  insert(payload_size, it);
-  payload_->Serialize(it);
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
deleted file mode 100644
index a2d8561..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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 <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/sco.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// SCO data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.3
-class ScoPacketBuilder : public HciPacketBuilder {
- public:
-  virtual ~ScoPacketBuilder() override = default;
-
-  static std::unique_ptr<ScoPacketBuilder> Create(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
-                                                  std::unique_ptr<BasePacketBuilder> payload);
-
-  virtual size_t size() const override;
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- private:
-  ScoPacketBuilder(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
-                   std::unique_ptr<BasePacketBuilder> payload);
-  ScoPacketBuilder() = delete;
-  uint16_t handle_;
-  sco::PacketStatusFlagsType packet_status_flags_;
-  std::unique_ptr<BasePacketBuilder> payload_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
deleted file mode 100644
index 9516ef4..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/sco_packet_view.h"
-
-#include <base/logging.h>
-
-using test_vendor_lib::sco::PacketStatusFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-ScoPacketView::ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
-
-ScoPacketView ScoPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
-  return ScoPacketView(packet);
-}
-
-uint16_t ScoPacketView::GetHandle() const {
-  return begin().extract<uint16_t>() & 0xfff;
-}
-
-PacketStatusFlagsType ScoPacketView::GetPacketStatusFlags() const {
-  return static_cast<PacketStatusFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
-}
-
-PacketView<true> ScoPacketView::GetPayload() const {
-  uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
-  CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
-      << "Malformed SCO packet payload_size " << payload_size << " + 4 != " << size();
-  return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
deleted file mode 100644
index 26b9489..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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 <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/sco.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// SCO data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.3
-class ScoPacketView : public PacketView<true> {
- public:
-  virtual ~ScoPacketView() override = default;
-
-  static ScoPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
-
-  uint16_t GetHandle() const;
-  sco::PacketStatusFlagsType GetPacketStatusFlags() const;
-  PacketView<true> GetPayload() const;
-
- private:
-  ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
-  ScoPacketView() = delete;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
deleted file mode 100644
index fb34489..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
-#include "packets/hci/acl_packet_view.h"
-#include "packets/raw_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace {
-vector<uint8_t> count = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-vector<uint8_t> information_request = {
-    0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
-};
-
-}  // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class AclBuilderTest : public ::testing::Test {
- public:
-  AclBuilderTest() = default;
-  ~AclBuilderTest() override = default;
-};
-
-TEST(AclBuilderTest, buildAclCountTest) {
-  uint16_t handle = 0x0102;
-  PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
-  BroadcastFlagsType broadcast_flags = BroadcastFlagsType::ACTIVE_SLAVE_BROADCAST;
-
-  std::unique_ptr<RawBuilder> count_payload = std::make_unique<RawBuilder>();
-  count_payload->AddOctets(count);
-  ASSERT_EQ(count.size(), count_payload->size());
-
-  std::unique_ptr<AclPacketBuilder> count_packet =
-      AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(count_payload));
-
-  ASSERT_EQ(count.size() + 4, count_packet->size());
-
-  std::shared_ptr<std::vector<uint8_t>> count_packet_bytes = count_packet->ToVector();
-  AclPacketView count_packet_view = AclPacketView::Create(count_packet_bytes);
-
-  ASSERT_EQ(handle, count_packet_view.GetHandle());
-  ASSERT_EQ(packet_boundary_flags, count_packet_view.GetPacketBoundaryFlags());
-  ASSERT_EQ(broadcast_flags, count_packet_view.GetBroadcastFlags());
-  PacketView<true> count_view = count_packet_view.GetPayload();
-
-  ASSERT_EQ(count_view.size(), count.size());
-  for (size_t i = 0; i < count_view.size(); i++) {
-    ASSERT_EQ(count_view[i], count[i]);
-  }
-}
-
-TEST(AclBuilderTest, buildInformationRequest) {
-  uint16_t handle = 0x0efe;
-  PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
-  BroadcastFlagsType broadcast_flags = BroadcastFlagsType::POINT_TO_POINT;
-
-  std::vector<uint8_t> payload_bytes(information_request.begin() + 4, information_request.end());
-  std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
-  payload->AddOctets(payload_bytes);
-  ASSERT_EQ(payload_bytes.size(), payload->size());
-
-  std::unique_ptr<AclPacketBuilder> packet =
-      AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(payload));
-
-  ASSERT_EQ(information_request.size(), packet->size());
-
-  std::shared_ptr<std::vector<uint8_t>> packet_bytes = packet->ToVector();
-  AclPacketView packet_view = AclPacketView::Create(packet_bytes);
-
-  ASSERT_EQ(packet_bytes->size(), information_request.size());
-  for (size_t i = 0; i < packet_bytes->size(); i++) {
-    ASSERT_EQ((*packet_bytes)[i], information_request[i]);
-  }
-
-  ASSERT_EQ(handle, packet_view.GetHandle());
-  ASSERT_EQ(packet_boundary_flags, packet_view.GetPacketBoundaryFlags());
-  ASSERT_EQ(broadcast_flags, packet_view.GetBroadcastFlags());
-  PacketView<true> payload_view = packet_view.GetPayload();
-
-  ASSERT_EQ(payload_view.size(), payload_bytes.size());
-  for (size_t i = 0; i < payload_view.size(); i++) {
-    ASSERT_EQ(payload_view[i], payload_bytes[i]);
-  }
-
-  ASSERT_EQ(packet_view.size(), information_request.size());
-  for (size_t i = 0; i < packet_view.size(); i++) {
-    ASSERT_EQ(packet_view[i], information_request[i]);
-  }
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
deleted file mode 100644
index 8a11d45..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/event_packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-}  // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EventBuilderTest : public ::testing::Test {
- public:
-  EventBuilderTest() = default;
-  ~EventBuilderTest() override = default;
-};
-
-TEST(EventBuilderTest, buildLeAdvertisementSmallTest) {
-  LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
-  LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
-  std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
-  Address addr({1, 2, 3, 4, 5, 6});
-  uint8_t rssi = -93;
-
-  std::vector<uint8_t> payload({0x23});
-  le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, {payload}, rssi);
-
-  uint8_t payload_size = payload.size();
-  uint8_t event_size = payload_size + sizeof(Address) + sizeof(rssi) + 5;
-  std::vector<uint8_t> expected({
-      0x3e,  // HCI LE Event
-      event_size,
-      0x02,          // LE Advertising subevent code
-      0x01,          // Number of responses
-      0x02,          // Event type is scannable undirected
-      0x01,          // Address type is random
-      0x01,          // Address
-      0x02,          // Address
-      0x03,          // Address
-      0x04,          // Address
-      0x05,          // Address
-      0x06,          // Address
-      payload_size,  // Length of the data
-  });
-
-  expected.push_back(payload[0]);
-  expected.push_back(rssi);
-
-  ASSERT_EQ(expected.size(), le_adv->size());
-  ASSERT_EQ(expected, *le_adv->ToVector());
-}
-
-TEST(EventBuilderTest, buildLeAdvertisementTest) {
-  LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
-  LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
-  std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
-  Address addr({1, 2, 3, 4, 5, 6});
-  uint8_t rssi = -93;
-
-  le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, count, rssi);
-
-  uint8_t count_size = static_cast<uint8_t>(count.size());
-  uint8_t event_size = count_size + sizeof(Address) + sizeof(rssi) + 5;
-  std::vector<uint8_t> expected({
-      0x3e,  // HCI LE Event
-      event_size,
-      0x02,        // LE Advertising subevent code
-      0x01,        // Number of responses
-      0x02,        // Event type is scannable undirected
-      0x01,        // Address type is random
-      0x01,        // Address
-      0x02,        // Address
-      0x03,        // Address
-      0x04,        // Address
-      0x05,        // Address
-      0x06,        // Address
-      count_size,  // Length of the data
-  });
-
-  for (size_t i = 0; i < count.size(); i++) {
-    expected.push_back(count[i]);
-  }
-  expected.push_back(rssi);
-
-  std::shared_ptr<std::vector<uint8_t>> raw_adv = le_adv->ToVector();
-  ASSERT_EQ(expected, *raw_adv);
-}
-
-TEST(EventBuilderTest, buildNumberOfCompletedPackets) {
-  uint16_t handle = 0x0102;
-  uint16_t num_packets = 0x0304;
-
-  std::unique_ptr<EventPacketBuilder> event =
-      EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
-
-  uint8_t number_of_handles = 1;
-  uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
-  std::vector<uint8_t> expected({
-      0x13,                           // HCI Number Of Completed Packets Event code
-      event_size, number_of_handles,  //
-      0x02, 0x01,                     // handle
-      0x04, 0x03,                     // count
-  });
-
-  std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
-  ASSERT_EQ(expected, *raw_event);
-}
-
-TEST(EventBuilderTest, buildNumberOfCompletedPacketsMultiple) {
-  uint16_t handle = 0x0102;
-  uint16_t num_packets = 0x0304;
-  uint16_t handle2 = 0x0506;
-  uint16_t num_packets2 = 0x0708;
-
-  std::unique_ptr<EventPacketBuilder> event =
-      EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
-  event->AddCompletedPackets(handle2, num_packets2);
-
-  uint8_t number_of_handles = 2;
-  uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
-  std::vector<uint8_t> expected({
-      0x13,                           // HCI Number Of Completed Packets Event code
-      event_size, number_of_handles,  //
-      0x02, 0x01,                     // handle
-      0x04, 0x03,                     // count
-      0x06, 0x05,                     // handle
-      0x08, 0x07,                     // count
-  });
-
-  std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
-  ASSERT_EQ(expected, *raw_event);
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.cc b/vendor_libs/test_vendor_lib/packets/iterator.cc
index 65173ee..dca3c82 100644
--- a/vendor_libs/test_vendor_lib/packets/iterator.cc
+++ b/vendor_libs/test_vendor_lib/packets/iterator.cc
@@ -16,7 +16,7 @@
 
 #include "iterator.h"
 
-#include <base/logging.h>
+#include "os/log.h"
 
 namespace test_vendor_lib {
 namespace packets {
@@ -131,7 +131,7 @@
 
 template <bool little_endian>
 uint8_t Iterator<little_endian>::operator*() const {
-  CHECK(index_ < length_) << "Index " << index_ << " out of bounds: " << length_;
+  ASSERT_LOG(index_ < length_, "Index %d out of bounds: %d", static_cast<int>(index_), static_cast<int>(length_));
   size_t index = index_;
 
   for (auto view : data_) {
@@ -140,7 +140,7 @@
     }
     index -= view.size();
   }
-  CHECK(false) << "Out of fragments searching for Index " << index_;
+  LOG_ALWAYS_FATAL("Out of fragments searching for Index %d", static_cast<int>(index_));
   return 0;
 }
 
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.h b/vendor_libs/test_vendor_lib/packets/iterator.h
index b84ce64..2f01fb9 100644
--- a/vendor_libs/test_vendor_lib/packets/iterator.h
+++ b/vendor_libs/test_vendor_lib/packets/iterator.h
@@ -19,12 +19,14 @@
 #include <cstdint>
 #include <forward_list>
 
-#include "types/address.h"
+#include "hci/address.h"
 #include "view.h"
 
 namespace test_vendor_lib {
 namespace packets {
 
+using ::bluetooth::hci::Address;
+
 // Templated Iterator for endianness
 template <bool little_endian>
 class Iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
deleted file mode 100644
index 15a4ab8..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CommandBuilder : public PacketBuilder<true> {
- public:
-  virtual ~CommandBuilder() = default;
-
-  static std::unique_ptr<CommandBuilder> Create(uint16_t opcode, PacketView<true> args) {
-    return std::unique_ptr<CommandBuilder>(new CommandBuilder(opcode, args));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(opcode_) + args_.size();
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(opcode_, it);
-    for (const auto&& byte : args_) {
-      insert(byte, it);
-    }
-  }
-
- private:
-  explicit CommandBuilder(uint16_t opcode, PacketView<true> args) : opcode_(opcode), args_(args) {}
-  uint16_t opcode_;
-  PacketView<true> args_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
deleted file mode 100644
index 0aa5683..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include <log/log.h>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CommandView : public PacketView<true> {
- public:
-  CommandView(const CommandView&) = default;
-  virtual ~CommandView() = default;
-
-  static CommandView GetCommand(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::COMMAND);
-    return CommandView(view.GetPayload());
-  }
-
-  uint16_t GetOpcode() {
-    return begin().extract<uint16_t>();
-  }
-
-  Iterator<true> GetData() {
-    return begin() + sizeof(uint16_t);
-  }
-
- private:
-  CommandView() = delete;
-  CommandView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
deleted file mode 100644
index 3c5a9f4..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class DisconnectBuilder : public PacketBuilder<true> {
- public:
-  virtual ~DisconnectBuilder() = default;
-
-  static std::unique_ptr<DisconnectBuilder> Create(uint8_t reason) {
-    return std::unique_ptr<DisconnectBuilder>(new DisconnectBuilder(reason));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(reason_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    *it++ = reason_;
-  }
-
- private:
-  explicit DisconnectBuilder(uint8_t reason) : reason_(reason) {}
-  uint8_t reason_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
deleted file mode 100644
index cdfcdc5..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class DisconnectView : public PacketView<true> {
- public:
-  DisconnectView(const DisconnectView&) = default;
-  virtual ~DisconnectView() = default;
-
-  static DisconnectView GetDisconnect(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::DISCONNECT);
-    return DisconnectView(view.GetPayload());
-  }
-
-  uint8_t GetReason() {
-    return at(0);
-  }
-
- private:
-  DisconnectView() = delete;
-  DisconnectView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
deleted file mode 100644
index 329ecdb..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EncryptConnectionBuilder : public PacketBuilder<true> {
- public:
-  virtual ~EncryptConnectionBuilder() = default;
-
-  static std::unique_ptr<EncryptConnectionBuilder> Create(const std::vector<uint8_t>& key) {
-    return std::unique_ptr<EncryptConnectionBuilder>(new EncryptConnectionBuilder(key));
-  }
-
-  virtual size_t size() const override {
-    return key_.size();
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert_vector(key_, it);
-  }
-
- private:
-  explicit EncryptConnectionBuilder(const std::vector<uint8_t>& key) : key_(key.begin(), key.begin() + 16) {}
-  std::vector<uint8_t> key_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
deleted file mode 100644
index 665fe98..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EncryptConnectionView : public PacketView<true> {
- public:
-  EncryptConnectionView(const EncryptConnectionView&) = default;
-  virtual ~EncryptConnectionView() = default;
-
-  static EncryptConnectionView GetEncryptConnection(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::ENCRYPT_CONNECTION ||
-          view.GetType() == Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
-    return EncryptConnectionView(view.GetPayload());
-  }
-
-  Iterator<true> GetKey() {
-    return begin();
-  }
-
- private:
-  EncryptConnectionView() = delete;
-  EncryptConnectionView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
deleted file mode 100644
index 6703316..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "inquiry.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryBuilder : public PacketBuilder<true> {
- public:
-  virtual ~InquiryBuilder() = default;
-
-  static std::unique_ptr<InquiryBuilder> Create(Inquiry::InquiryType inquiry_type) {
-    return std::unique_ptr<InquiryBuilder>(new InquiryBuilder(inquiry_type));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(uint8_t);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(static_cast<uint8_t>(inquiry_type_), it);
-  }
-
- private:
-  explicit InquiryBuilder(Inquiry::InquiryType inquiry_type) : inquiry_type_(inquiry_type) {}
-  Inquiry::InquiryType inquiry_type_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
deleted file mode 100644
index 694fe71..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "include/inquiry.h"
-#include "packets/packet_builder.h"
-#include "types/class_of_device.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryResponseBuilder : public PacketBuilder<true> {
- public:
-  virtual ~InquiryResponseBuilder() = default;
-
-  static std::unique_ptr<InquiryResponseBuilder> CreateStandard(uint8_t page_scan_repetition_mode,
-                                                                const ClassOfDevice& class_of_device,
-                                                                uint16_t clock_offset) {
-    return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
-        Inquiry::InquiryType::STANDARD, page_scan_repetition_mode, class_of_device, clock_offset));
-  }
-  static std::unique_ptr<InquiryResponseBuilder> CreateRssi(uint8_t page_scan_repetition_mode,
-                                                            const ClassOfDevice& class_of_device, uint16_t clock_offset,
-                                                            uint8_t rssi) {
-    return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
-        Inquiry::InquiryType::RSSI, page_scan_repetition_mode, class_of_device, clock_offset, rssi));
-  }
-  static std::unique_ptr<InquiryResponseBuilder> CreateExtended(uint8_t page_scan_repetition_mode,
-                                                                const ClassOfDevice& class_of_device,
-                                                                uint16_t clock_offset, uint8_t rssi,
-                                                                const std::vector<uint8_t>& extended_data) {
-    return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
-        Inquiry::InquiryType::EXTENDED, page_scan_repetition_mode, class_of_device, clock_offset, rssi, extended_data));
-  }
-
-  virtual size_t size() const override {
-    size_t inquiry_size =
-        sizeof(inquiry_type_) + sizeof(page_scan_repetition_mode_) + sizeof(class_of_device_) + sizeof(clock_offset_);
-    if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
-      return inquiry_size;
-    }
-    inquiry_size += sizeof(rssi_);
-    if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
-      return inquiry_size;
-    }
-
-    return inquiry_size + extended_data_.size();
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(static_cast<uint8_t>(inquiry_type_), it);
-    insert(page_scan_repetition_mode_, it);
-    insert_class_of_device(class_of_device_, it);
-    insert(clock_offset_, it);
-    if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
-      return;
-    }
-    insert(rssi_, it);
-    if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
-      return;
-    }
-    insert_vector(extended_data_, it);
-  }
-
- private:
-  Inquiry::InquiryType inquiry_type_;
-  uint8_t page_scan_repetition_mode_;
-  ClassOfDevice class_of_device_;
-  uint16_t clock_offset_;
-  uint8_t rssi_{0xff};
-  std::vector<uint8_t> extended_data_;
-  explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
-                                  const ClassOfDevice& class_of_device, uint16_t clock_offset)
-      : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
-        class_of_device_(class_of_device), clock_offset_(clock_offset) {}
-  explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
-                                  const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi)
-      : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
-        class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi) {}
-  explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
-                                  const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi,
-                                  const std::vector<uint8_t>& extended_data)
-      : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
-        class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi), extended_data_(extended_data) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
deleted file mode 100644
index aac0585..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "include/inquiry.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryResponseView : public PacketView<true> {
- public:
-  InquiryResponseView(const InquiryResponseView&) = default;
-  virtual ~InquiryResponseView() = default;
-
-  static InquiryResponseView GetInquiryResponse(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::INQUIRY_RESPONSE);
-    return InquiryResponseView(view.GetPayload());
-  }
-
-  Inquiry::InquiryType GetType() {
-    return static_cast<Inquiry::InquiryType>(at(0));
-  }
-
-  uint8_t GetPageScanRepetitionMode() {
-    return at(1);
-  }
-
-  ClassOfDevice GetClassOfDevice() {
-    size_t offset = 2 * sizeof(uint8_t);
-    return (begin() + offset).extract<ClassOfDevice>();
-  }
-
-  uint16_t GetClockOffset() {
-    size_t offset = 2 * sizeof(uint8_t) + 3;
-    return (begin() + offset).extract<uint16_t>();
-  }
-
-  uint8_t GetRssi() {
-    size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t);
-    return at(offset);
-  }
-
-  Iterator<true> GetExtendedData() {
-    size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t) + sizeof(uint8_t);
-    return begin() + offset;
-  }
-
- private:
-  InquiryResponseView() = delete;
-  InquiryResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
deleted file mode 100644
index eee861c..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "inquiry.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryView : public PacketView<true> {
- public:
-  InquiryView(const InquiryView&) = default;
-  virtual ~InquiryView() = default;
-
-  static InquiryView GetInquiry(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::INQUIRY);
-    return InquiryView(view.GetPayload());
-  }
-
-  Inquiry::InquiryType GetType() {
-    return static_cast<Inquiry::InquiryType>(at(0));
-  }
-
- private:
-  InquiryView() = delete;
-  InquiryView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
deleted file mode 100644
index 79efb50..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityBuilder : public PacketBuilder<true> {
- public:
-  virtual ~IoCapabilityBuilder() = default;
-
-  static std::unique_ptr<IoCapabilityBuilder> Create(uint8_t io_capability, uint8_t oob_data_present,
-                                                     uint8_t authentication_requirements) {
-    return std::unique_ptr<IoCapabilityBuilder>(
-        new IoCapabilityBuilder(io_capability, oob_data_present, authentication_requirements));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(io_capability_) + sizeof(oob_data_present_) + sizeof(authentication_requirements_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(io_capability_, it);
-    insert(oob_data_present_, it);
-    insert(authentication_requirements_, it);
-  }
-
- private:
-  explicit IoCapabilityBuilder(uint8_t io_capability, uint8_t oob_data_present, uint8_t authentication_requirements)
-      : io_capability_(io_capability), oob_data_present_(oob_data_present),
-        authentication_requirements_(authentication_requirements) {}
-  uint8_t io_capability_;
-  uint8_t oob_data_present_;
-  uint8_t authentication_requirements_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
deleted file mode 100644
index c9e7601..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityNegativeResponseBuilder : public PacketBuilder<true> {
- public:
-  virtual ~IoCapabilityNegativeResponseBuilder() = default;
-
-  static std::unique_ptr<IoCapabilityNegativeResponseBuilder> Create(uint8_t reason) {
-    return std::unique_ptr<IoCapabilityNegativeResponseBuilder>(new IoCapabilityNegativeResponseBuilder(reason));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(reason_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(reason_, it);
-  }
-
- private:
-  explicit IoCapabilityNegativeResponseBuilder(uint8_t reason) : reason_(reason) {}
-  uint8_t reason_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
deleted file mode 100644
index 27c888f..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityNegativeResponseView : public PacketView<true> {
- public:
-  IoCapabilityNegativeResponseView(const IoCapabilityNegativeResponseView&) = default;
-  virtual ~IoCapabilityNegativeResponseView() = default;
-
-  static IoCapabilityNegativeResponseView GetIoCapabilityNegativeResponse(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
-    return IoCapabilityNegativeResponseView(view.GetPayload());
-  }
-
-  uint8_t GetReason() {
-    return at(0);
-  }
-
- private:
-  IoCapabilityNegativeResponseView() = delete;
-  IoCapabilityNegativeResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
deleted file mode 100644
index 66c7564..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityView : public PacketView<true> {
- public:
-  IoCapabilityView(const IoCapabilityView&) = default;
-  virtual ~IoCapabilityView() = default;
-
-  static IoCapabilityView GetIoCapability(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_RESPONSE ||
-          view.GetType() == Link::PacketType::IO_CAPABILITY_REQUEST);
-    return IoCapabilityView(view.GetPayload());
-  }
-
-  uint8_t GetIoCapability() {
-    return at(0);
-  }
-  uint8_t GetOobDataPresent() {
-    return at(1);
-  }
-  uint8_t GetAuthenticationRequirements() {
-    return at(2);
-  }
-
- private:
-  IoCapabilityView() = delete;
-  IoCapabilityView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
deleted file mode 100644
index 18b3167..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "include/le_advertisement.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LeAdvertisementBuilder : public PacketBuilder<true>, public LeAdvertisement {
- public:
-  virtual ~LeAdvertisementBuilder() = default;
-
-  static std::unique_ptr<LeAdvertisementBuilder> Create(AddressType address_type, AdvertisementType advertisement_type,
-                                                        const std::vector<uint8_t>& advertisement) {
-    return std::unique_ptr<LeAdvertisementBuilder>(
-        new LeAdvertisementBuilder(address_type, advertisement_type, advertisement));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(address_type_) + sizeof(advertisement_type_) + advertisement_.size();
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(static_cast<uint8_t>(address_type_), it);
-    insert(static_cast<uint8_t>(advertisement_type_), it);
-    insert_vector(advertisement_, it);
-  }
-
- private:
-  LeAdvertisementBuilder() = delete;
-  explicit LeAdvertisementBuilder(AddressType address_type, AdvertisementType advertisement_type,
-                                  const std::vector<uint8_t>& advertisement)
-      : address_type_(address_type), advertisement_type_(advertisement_type), advertisement_(advertisement) {}
-  AddressType address_type_;
-  AdvertisementType advertisement_type_;
-  std::vector<uint8_t> advertisement_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
deleted file mode 100644
index 80e0367..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include <log/log.h>
-
-#include "include/link.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LeAdvertisementView : public PacketView<true>, public LeAdvertisement {
- public:
-  LeAdvertisementView(const LeAdvertisementView&) = default;
-  virtual ~LeAdvertisementView() = default;
-
-  static LeAdvertisementView GetLeAdvertisementView(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::LE_ADVERTISEMENT || view.GetType() == Link::PacketType::LE_SCAN_RESPONSE);
-    return LeAdvertisementView(view.GetPayload());
-  }
-
-  AddressType GetAddressType() {
-    return static_cast<AddressType>(at(0));
-  }
-  AdvertisementType GetAdvertisementType() {
-    return static_cast<AdvertisementType>(at(1));
-  }
-  Iterator<true> GetData() {
-    return begin() + 2 * sizeof(uint8_t);
-  }
-
- private:
-  LeAdvertisementView() = delete;
-  LeAdvertisementView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
deleted file mode 100644
index 5c5536f..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2018 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 "link_layer_packet_builder.h"
-#include "link_layer_packet_view.h"
-
-#include "base/logging.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-namespace packets {
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest)
-    : type_(type), source_addr_(source), dest_addr_(dest) {}
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
-                                               const Address& source)
-    : type_(type), source_addr_(source), dest_addr_(Address::kEmpty), builder_(std::move(packet)) {}
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
-                                               const Address& source, const Address& dest)
-    : type_(type), source_addr_(source), dest_addr_(dest), builder_(std::move(packet)) {}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
-                                                                        const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::ACL, std::move(acl), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapCommand(std::unique_ptr<CommandBuilder> command,
-                                                                            const Address& source,
-                                                                            const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::COMMAND, std::move(command), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapDisconnect(
-    std::unique_ptr<DisconnectBuilder> disconnect, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::DISCONNECT, std::move(disconnect), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnection(
-    std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::ENCRYPT_CONNECTION, std::move(encrypt_connection), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
-    std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
-      Link::PacketType::ENCRYPT_CONNECTION_RESPONSE, std::move(encrypt_connection), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
-                                                                            const Address& source) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::INQUIRY, std::move(inquiry), source));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiryResponse(
-    std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::INQUIRY_RESPONSE, std::move(inquiry_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityRequest(
-    std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_REQUEST, std::move(io_capability), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityResponse(
-    std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_RESPONSE, std::move(io_capability), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
-    std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
-    const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
-      Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE, std::move(io_capability_negative_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeAdvertisement(
-    std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::LE_ADVERTISEMENT, std::move(advertisement), source));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScan(const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN, source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScanResponse(
-    std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN_RESPONSE, std ::move(scan_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPage(std::unique_ptr<PageBuilder> page,
-                                                                         const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::PAGE, std::move(page), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageReject(
-    std::unique_ptr<PageRejectBuilder> page_reject, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::PAGE_REJECT, std::move(page_reject), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageResponse(
-    std::unique_ptr<PageResponseBuilder> page_response, const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::PAGE_RESPONSE, std::move(page_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapResponse(std::unique_ptr<ResponseBuilder> response,
-                                                                             const Address& source,
-                                                                             const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::RESPONSE, std::move(response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
-                                                                        const Address& source, const Address& dest) {
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(Link::PacketType::SCO, std::move(sco), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::ReWrap(
-    const std::shared_ptr<std::vector<uint8_t>> raw_packet) {
-  LinkLayerPacketView received = LinkLayerPacketView::Create(raw_packet);
-  Link::PacketType packet_type = received.GetType();
-  Address source = received.GetSourceAddress();
-  Address dest = received.GetDestinationAddress();
-  PacketView<true> payload = received.GetPayload();
-  std::unique_ptr<PacketBuilder> builder = ViewForwarderBuilder::Create(payload);
-  return std::shared_ptr<LinkLayerPacketBuilder>(
-      new LinkLayerPacketBuilder(packet_type, std::move(builder), source, dest));
-}
-
-size_t LinkLayerPacketBuilder::size() const {
-  size_t builder_size = (builder_ ? builder_->size() : 0);
-  return Link::kTypeBytes + Link::kSizeBytes + 2 * Address::kLength + builder_size;
-}
-
-void LinkLayerPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
-  insert(static_cast<uint32_t>(size() - Link::kSizeBytes), it);
-  insert(static_cast<uint8_t>(type_), it);
-  insert_address(source_addr_.address, it);
-  insert_address(dest_addr_.address, it);
-  if (builder_) {
-    builder_->Serialize(it);
-  }
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
deleted file mode 100644
index 4ebbaba..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <string>
-#include <vector>
-
-#include "link.h"
-#include "packets/link_layer/command_builder.h"
-#include "packets/link_layer/disconnect_builder.h"
-#include "packets/link_layer/encrypt_connection_builder.h"
-#include "packets/link_layer/inquiry_builder.h"
-#include "packets/link_layer/inquiry_response_builder.h"
-#include "packets/link_layer/io_capability_builder.h"
-#include "packets/link_layer/io_capability_negative_response_builder.h"
-#include "packets/link_layer/le_advertisement_builder.h"
-#include "packets/link_layer/page_builder.h"
-#include "packets/link_layer/page_reject_builder.h"
-#include "packets/link_layer/page_response_builder.h"
-#include "packets/link_layer/response_builder.h"
-#include "packets/link_layer/view_forwarder_builder.h"
-#include "packets/packet_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Link-layer packets are an abstraction of LMP PDUs.
-class LinkLayerPacketBuilder : PacketBuilder<true> {
- public:
-  virtual ~LinkLayerPacketBuilder() = default;
-
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
-                                                         const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapCommand(std::unique_ptr<CommandBuilder> command,
-                                                             const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapDisconnect(std::unique_ptr<DisconnectBuilder> disconnect,
-                                                                const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnection(
-      std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnectionResponse(
-      std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
-                                                             const Address& source);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiryResponse(
-      std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityRequest(
-      std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityResponse(
-      std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityNegativeResponse(
-      std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
-      const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapLeAdvertisement(
-      std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScan(const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScanResponse(
-      std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapPage(std::unique_ptr<PageBuilder> page, const Address& source,
-                                                          const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapPageReject(std::unique_ptr<PageRejectBuilder> page_response,
-                                                                const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapPageResponse(std::unique_ptr<PageResponseBuilder> page_response,
-                                                                  const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapResponse(const std::unique_ptr<ResponseBuilder> response,
-                                                              const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
-                                                         const Address& source, const Address& dest);
-  static std::shared_ptr<LinkLayerPacketBuilder> ReWrap(const std::shared_ptr<std::vector<uint8_t>> raw_packet);
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
-  virtual size_t size() const override;
-
- private:
-  LinkLayerPacketBuilder(const LinkLayerPacketBuilder&) = delete;
-  LinkLayerPacketBuilder() = delete;
-  LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest);
-  LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source,
-                         const Address& dest);
-  LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source);
-  Link::PacketType type_;
-  Address source_addr_;
-  Address dest_addr_;
-  std::unique_ptr<PacketBuilder> builder_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
deleted file mode 100644
index 04518ca..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 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 "link_layer_packet_view.h"
-#include "base/logging.h"
-
-namespace test_vendor_lib {
-constexpr size_t Link::kSizeBytes;
-constexpr size_t Link::kTypeBytes;
-
-namespace packets {
-LinkLayerPacketView::LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw) : PacketView<true>(raw) {}
-
-LinkLayerPacketView LinkLayerPacketView::Create(std::shared_ptr<std::vector<uint8_t>> raw) {
-  CHECK(raw->size() >= Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength);
-  return LinkLayerPacketView(raw);
-}
-
-Link::PacketType LinkLayerPacketView::GetType() const {
-  return static_cast<Link::PacketType>(at(Link::kSizeBytes));
-}
-
-Address LinkLayerPacketView::GetSourceAddress() const {
-  size_t offset = Link::kSizeBytes + Link::kTypeBytes;
-  return (begin() + offset).extract<Address>();
-}
-
-Address LinkLayerPacketView::GetDestinationAddress() const {
-  size_t offset = Link::kSizeBytes + Link::kTypeBytes + Address::kLength;
-  return (begin() + offset).extract<Address>();
-}
-
-PacketView<true> LinkLayerPacketView::GetPayload() const {
-  return SubViewLittleEndian(Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength, size());
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
deleted file mode 100644
index bdbfaa7..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <string>
-#include <vector>
-
-#include "include/link.h"
-#include "packets/packet_view.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Link-layer packets are an abstraction of LMP PDUs.
-class LinkLayerPacketView : public PacketView<true> {
- public:
-  LinkLayerPacketView(const LinkLayerPacketView&) = default;
-  virtual ~LinkLayerPacketView() = default;
-
-  static LinkLayerPacketView Create(std::shared_ptr<std::vector<uint8_t>> raw);
-
-  Link::PacketType GetType() const;
-  Address GetSourceAddress() const;
-  Address GetDestinationAddress() const;
-  PacketView<true> GetPayload() const;
-
- private:
-  LinkLayerPacketView() = delete;
-  LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw);
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
deleted file mode 100644
index 0e18cb3..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include <base/logging.h>
-
-#include "packets/packet_builder.h"
-#include "types/class_of_device.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageBuilder : public PacketBuilder<true> {
- public:
-  virtual ~PageBuilder() = default;
-
-  static std::unique_ptr<PageBuilder> Create(const ClassOfDevice& class_of_device, uint8_t allow_role_switch) {
-    return std::unique_ptr<PageBuilder>(new PageBuilder(class_of_device, allow_role_switch));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(class_of_device_) + sizeof(allow_role_switch_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert_class_of_device(class_of_device_, it);
-    insert(allow_role_switch_, it);
-  }
-
- private:
-  explicit PageBuilder(const ClassOfDevice& class_of_device, uint8_t allow_role_switch)
-      : class_of_device_(class_of_device), allow_role_switch_(allow_role_switch) {}
-  ClassOfDevice class_of_device_;
-  uint8_t allow_role_switch_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h
deleted file mode 100644
index ebf84d2..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_builder.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 <cstdint>
-#include <memory>
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageRejectBuilder : public PacketBuilder<true> {
- public:
-  virtual ~PageRejectBuilder() = default;
-
-  static std::unique_ptr<PageRejectBuilder> Create(uint8_t reason) {
-    return std::unique_ptr<PageRejectBuilder>(new PageRejectBuilder(reason));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(reason_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(reason_, it);
-  }
-
- private:
-  explicit PageRejectBuilder(uint8_t reason) : reason_(reason) {}
-  uint8_t reason_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h
deleted file mode 100644
index d7afe5b..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_reject_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageRejectView : public PacketView<true> {
- public:
-  PageRejectView(const PageRejectView&) = default;
-  virtual ~PageRejectView() = default;
-
-  static PageRejectView GetPageReject(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::PAGE_REJECT);
-    return PageRejectView(view.GetPayload());
-  }
-
-  uint8_t GetReason() {
-    return at(0);
-  }
-
- private:
-  PageRejectView() = delete;
-  PageRejectView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
deleted file mode 100644
index 78f9a80..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageResponseBuilder : public PacketBuilder<true> {
- public:
-  virtual ~PageResponseBuilder() = default;
-
-  static std::unique_ptr<PageResponseBuilder> Create(uint8_t try_role_switch) {
-    return std::unique_ptr<PageResponseBuilder>(new PageResponseBuilder(try_role_switch));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(try_role_switch_);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(try_role_switch_, it);
-  }
-
- private:
-  explicit PageResponseBuilder(uint8_t try_role_switch) : try_role_switch_(try_role_switch) {}
-  uint8_t try_role_switch_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
deleted file mode 100644
index 20f0b68..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageResponseView : public PacketView<true> {
- public:
-  PageResponseView(const PageResponseView&) = default;
-  virtual ~PageResponseView() = default;
-
-  static PageResponseView GetPageResponse(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::PAGE_RESPONSE);
-    return PageResponseView(view.GetPayload());
-  }
-
-  uint8_t GetTryRoleSwitch() {
-    return at(0);
-  }
-
- private:
-  PageResponseView() = delete;
-  PageResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
deleted file mode 100644
index a26446d..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageView : public PacketView<true> {
- public:
-  PageView(const PageView&) = default;
-  virtual ~PageView() = default;
-
-  static PageView GetPage(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::PAGE);
-    return PageView(view.GetPayload());
-  }
-
-  ClassOfDevice GetClassOfDevice() {
-    return begin().extract<ClassOfDevice>();
-  }
-
-  uint8_t GetAllowRoleSwitch() {
-    return at(3);
-  }
-
- private:
-  PageView() = delete;
-  PageView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
deleted file mode 100644
index 18f765d..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-#include <vector>
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ResponseBuilder : public PacketBuilder<true> {
- public:
-  virtual ~ResponseBuilder() = default;
-
-  static std::unique_ptr<ResponseBuilder> Create(uint16_t opcode, const std::vector<uint64_t>& data) {
-    return std::unique_ptr<ResponseBuilder>(new ResponseBuilder(opcode, data));
-  }
-
-  virtual size_t size() const override {
-    return sizeof(opcode_) + data_.size() * sizeof(uint64_t);
-  }
-
- protected:
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    insert(opcode_, it);
-    insert_vector(data_, it);
-  }
-
- private:
-  explicit ResponseBuilder(uint16_t opcode, const std::vector<uint64_t> data) : opcode_(opcode), data_(data) {}
-  uint16_t opcode_;
-  std::vector<uint64_t> data_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
deleted file mode 100644
index f1ff7c9..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-
-#include <log/log.h>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ResponseView : public PacketView<true> {
- public:
-  ResponseView(const ResponseView&) = default;
-  virtual ~ResponseView() = default;
-
-  static ResponseView GetResponse(const LinkLayerPacketView& view) {
-    CHECK(view.GetType() == Link::PacketType::RESPONSE);
-    return ResponseView(view.GetPayload());
-  }
-
-  uint16_t GetOpcode() {
-    return begin().extract<uint16_t>();
-  }
-
-  Iterator<true> GetResponseData() {
-    return begin() + sizeof(uint16_t);
-  }
-
- private:
-  ResponseView() = delete;
-  ResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
deleted file mode 100644
index da0d827..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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 <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ViewForwarderBuilder : public PacketBuilder<true> {
- public:
-  virtual ~ViewForwarderBuilder() = default;
-
-  static std::unique_ptr<ViewForwarderBuilder> Create(PacketView<true> view) {
-    return std::unique_ptr<ViewForwarderBuilder>(new ViewForwarderBuilder(view));
-  }
-
-  virtual size_t size() const override {
-    return view_.size();
-  }
-
-  virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
-    for (size_t i = 0; i < view_.size(); i++) {
-      insert(view_[i], it);
-    }
-  }
-
- private:
-  explicit ViewForwarderBuilder(PacketView<true> view) : view_(view) {}
-  PacketView<true> view_;
-};
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
new file mode 100644
index 0000000..2d601cd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
@@ -0,0 +1,236 @@
+little_endian_packets
+
+custom_field Address : 48 "hci/"
+custom_field ClassOfDevice : 24 "hci/"
+
+enum PacketType : 8 {
+    UNKNOWN = 0x00,
+    ACL = 0x01,
+    DISCONNECT = 0x02,
+    ENCRYPT_CONNECTION = 0x03,
+    ENCRYPT_CONNECTION_RESPONSE = 0x04,
+    EVENT = 0x05,
+    INQUIRY = 0x06,
+    INQUIRY_RESPONSE = 0x07,
+    IO_CAPABILITY_REQUEST = 0x08,
+    IO_CAPABILITY_RESPONSE = 0x09,
+    IO_CAPABILITY_NEGATIVE_RESPONSE = 0x0A,
+    LE_ADVERTISEMENT = 0x0B,
+    LE_CONNECT = 0x0C,
+    LE_CONNECT_COMPLETE = 0x0D,
+    LE_SCAN = 0x0E,
+    LE_SCAN_RESPONSE = 0x0F,
+    PAGE = 0x10,
+    PAGE_RESPONSE = 0x11,
+    PAGE_REJECT = 0x12,
+    READ_CLOCK_OFFSET = 0x13,
+    READ_CLOCK_OFFSET_RESPONSE = 0x14,
+    READ_REMOTE_SUPPORTED_FEATURES = 0x15,
+    READ_REMOTE_SUPPORTED_FEATURES_RESPONSE = 0x16,
+    READ_REMOTE_LMP_FEATURES = 0x17,
+    READ_REMOTE_LMP_FEATURES_RESPONSE = 0x18,
+    READ_REMOTE_EXTENDED_FEATURES = 0x19,
+    READ_REMOTE_EXTENDED_FEATURES_RESPONSE = 0x1A,
+    READ_REMOTE_VERSION_INFORMATION = 0x1B,
+    READ_REMOTE_VERSION_INFORMATION_RESPONSE = 0x1C,
+    REMOTE_NAME_REQUEST = 0x1D,
+    REMOTE_NAME_REQUEST_RESPONSE = 0x1E,
+    SCO = 0x1F,
+    COMMAND = 0x23, // Remove
+    RESPONSE = 0x24, // Remove
+}
+
+packet LinkLayerPacket {
+  type : PacketType,
+  source_address : Address,
+  destination_address : Address,
+  _body_,
+}
+
+packet Command : LinkLayerPacket (type = COMMAND) {
+  _payload_,
+}
+
+packet Response : LinkLayerPacket (type = RESPONSE) {
+  opcode : 16,
+  _payload_,
+}
+
+packet AclPacket : LinkLayerPacket (type = ACL) {
+  _payload_,
+}
+
+packet Disconnect : LinkLayerPacket (type = DISCONNECT) {
+  reason : 8,
+}
+
+packet EncryptConnection : LinkLayerPacket (type = ENCRYPT_CONNECTION) {
+  key : 8[],
+}
+
+packet EncryptConnectionResponse : LinkLayerPacket (type = ENCRYPT_CONNECTION_RESPONSE) {
+  key : 8[],
+}
+
+enum InquiryState : 8 {
+  STANDBY = 0x00,
+  INQUIRY = 0x01,
+}
+
+enum InquiryType : 8 {
+  STANDARD = 0x00,
+  RSSI = 0x01,
+  EXTENDED = 0x02,
+}
+
+packet Inquiry : LinkLayerPacket (type = INQUIRY) {
+  inquiry_type : InquiryType,
+}
+
+packet BasicInquiryResponse : LinkLayerPacket(type = INQUIRY_RESPONSE) {
+  inquiry_type : InquiryType,
+  page_scan_repetition_mode : 8,
+  class_of_device : ClassOfDevice,
+  clock_offset : 15,
+  _reserved_ : 1,
+  _body_,
+}
+
+packet InquiryResponse : BasicInquiryResponse (inquiry_type = STANDARD) {
+}
+
+packet InquiryResponseWithRssi : BasicInquiryResponse (inquiry_type = RSSI)  {
+  rssi: 8,
+}
+
+packet ExtendedInquiryResponse : BasicInquiryResponse (inquiry_type = EXTENDED)  {
+  rssi: 8,
+  extended_data : 8[],
+}
+
+packet IoCapabilityRequest : LinkLayerPacket (type = IO_CAPABILITY_REQUEST) {
+  io_capability : 8,
+  oob_data_present : 8,
+  authentication_requirements : 8,
+}
+
+packet IoCapabilityResponse : LinkLayerPacket (type = IO_CAPABILITY_RESPONSE) {
+  io_capability : 8,
+  oob_data_present : 8,
+  authentication_requirements : 8,
+}
+
+packet IoCapabilityNegativeResponse : LinkLayerPacket (type = IO_CAPABILITY_NEGATIVE_RESPONSE) {
+  reason : 8,
+}
+
+enum AddressType : 8 {
+  PUBLIC = 0,
+  RANDOM = 1,
+  PUBLIC_IDENTITY = 2,
+  RANDOM_IDENTITY = 3,
+}
+
+enum AdvertisementType : 8 {
+    ADV_IND = 0,          // Connectable and scannable
+    ADV_DIRECT_IND = 1,   // Connectable directed
+    ADV_SCAN_IND = 2,     // Scannable undirected
+    ADV_NONCONN_IND = 3,  // Non connectable undirected
+    SCAN_RESPONSE = 4,
+}
+
+packet LeAdvertisement : LinkLayerPacket (type = LE_ADVERTISEMENT) {
+  address_type : AddressType,
+  advertisement_type : AdvertisementType,
+  data : 8[],
+}
+
+packet LeConnect : LinkLayerPacket (type = LE_CONNECT) {
+  le_connection_interval_min : 16,
+  le_connection_interval_max : 16,
+  le_connection_latency : 16,
+  le_connection_supervision_timeout : 16,
+  address_type : 8,
+}
+
+packet LeConnectComplete : LinkLayerPacket (type = LE_CONNECT_COMPLETE) {
+  le_connection_interval : 16,
+  le_connection_latency : 16,
+  le_connection_supervision_timeout : 16,
+  address_type : 8,
+}
+
+packet LeScan : LinkLayerPacket (type = LE_SCAN) {
+}
+
+packet LeScanResponse : LinkLayerPacket (type = LE_SCAN_RESPONSE) {
+  address_type : AddressType,
+  advertisement_type : AdvertisementType,
+  data : 8[],
+}
+
+packet Page : LinkLayerPacket (type = PAGE) {
+  class_of_device : ClassOfDevice,
+  allow_role_switch : 8,
+}
+
+packet PageResponse : LinkLayerPacket (type = PAGE_RESPONSE) {
+  try_role_switch : 8,
+}
+
+packet PageReject : LinkLayerPacket (type = PAGE_REJECT) {
+  reason : 8,
+}
+
+packet ReadClockOffset : LinkLayerPacket (type = READ_CLOCK_OFFSET) {
+}
+
+packet ReadClockOffsetResponse : LinkLayerPacket (type = READ_CLOCK_OFFSET_RESPONSE) {
+  offset : 16,
+}
+
+packet ReadRemoteSupportedFeatures : LinkLayerPacket (type = READ_REMOTE_SUPPORTED_FEATURES) {
+}
+
+packet ReadRemoteSupportedFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_SUPPORTED_FEATURES_RESPONSE) {
+  features : 64,
+}
+
+packet ReadRemoteLmpFeatures : LinkLayerPacket (type = READ_REMOTE_LMP_FEATURES) {
+}
+
+packet ReadRemoteLmpFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_LMP_FEATURES_RESPONSE) {
+  features : 64,
+}
+
+packet ReadRemoteExtendedFeatures : LinkLayerPacket (type = READ_REMOTE_EXTENDED_FEATURES) {
+  page_number : 8,
+}
+
+packet ReadRemoteExtendedFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_EXTENDED_FEATURES_RESPONSE) {
+  status : 8,
+  page_number : 8,
+  max_page_number : 8,
+  features : 64,
+}
+
+packet ReadRemoteVersionInformation : LinkLayerPacket (type = READ_REMOTE_VERSION_INFORMATION) {
+}
+
+packet ReadRemoteVersionInformationResponse : LinkLayerPacket (type = READ_REMOTE_VERSION_INFORMATION_RESPONSE) {
+  lmp_version : 8,
+  lmp_subversion : 8,
+  manufacturer_name : 16,
+}
+
+packet RemoteNameRequest : LinkLayerPacket (type = REMOTE_NAME_REQUEST) {
+}
+
+packet RemoteNameRequestResponse : LinkLayerPacket (type = REMOTE_NAME_REQUEST_RESPONSE) {
+  name : 8[248],
+}
+
+packet ScoPacket : LinkLayerPacket (type = SCO) {
+  _payload_,
+}
+
diff --git a/vendor_libs/test_vendor_lib/packets/packet_builder.h b/vendor_libs/test_vendor_lib/packets/packet_builder.h
index 947b02a..44feac8 100644
--- a/vendor_libs/test_vendor_lib/packets/packet_builder.h
+++ b/vendor_libs/test_vendor_lib/packets/packet_builder.h
@@ -23,12 +23,14 @@
 #include <vector>
 
 #include "base_packet_builder.h"
-#include "types/address.h"
+#include "hci/address.h"
 #include "types/class_of_device.h"
 
 namespace test_vendor_lib {
 namespace packets {
 
+using ::bluetooth::hci::Address;
+
 // Abstract base class that is subclassed to build specifc packets.
 // The template parameter little_endian controls the generation of insert().
 template <bool little_endian>
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.cc b/vendor_libs/test_vendor_lib/packets/packet_view.cc
index 7ffe71a..65cd4e7 100644
--- a/vendor_libs/test_vendor_lib/packets/packet_view.cc
+++ b/vendor_libs/test_vendor_lib/packets/packet_view.cc
@@ -18,7 +18,7 @@
 
 #include <algorithm>
 
-#include <base/logging.h>
+#include "os/log.h"
 
 namespace test_vendor_lib {
 namespace packets {
@@ -52,14 +52,14 @@
 
 template <bool little_endian>
 uint8_t PacketView<little_endian>::at(size_t index) const {
-  CHECK(index < length_) << "Index " << index << " out of bounds";
+  ASSERT_LOG(index < length_, "Index %d out of bounds", static_cast<int>(index));
   for (const auto& fragment : fragments_) {
     if (index < fragment.size()) {
       return fragment[index];
     }
     index -= fragment.size();
   }
-  CHECK(false) << "Out of fragments searching for Index " << index;
+  LOG_ALWAYS_FATAL("Out of fragments searching for Index %d", static_cast<int>(index));
   return 0;
 }
 
@@ -70,8 +70,8 @@
 
 template <bool little_endian>
 std::forward_list<View> PacketView<little_endian>::SubViewList(size_t begin, size_t end) const {
-  CHECK(begin <= end) << "Begin " << begin << " is past end";
-  CHECK(end <= length_) << "End " << end << " is too large";
+  ASSERT_LOG(begin <= end, "Begin %d is past end %d", static_cast<int>(begin), static_cast<int>(end));
+  ASSERT_LOG(end <= length_, "End %d is too large", static_cast<int>(end));
   std::forward_list<View> view_list;
   std::forward_list<View>::iterator it = view_list.before_begin();
   size_t length = end - begin;
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.h b/vendor_libs/test_vendor_lib/packets/packet_view.h
index 16255fa..22c530a 100644
--- a/vendor_libs/test_vendor_lib/packets/packet_view.h
+++ b/vendor_libs/test_vendor_lib/packets/packet_view.h
@@ -32,6 +32,7 @@
 class PacketView {
  public:
   PacketView(const std::forward_list<class View> fragments);
+  PacketView(std::shared_ptr<std::vector<uint8_t>> packet);
   PacketView(const PacketView& PacketView) = default;
   virtual ~PacketView() = default;
 
@@ -49,9 +50,6 @@
 
   PacketView<false> SubViewBigEndian(size_t begin, size_t end) const;
 
- protected:
-  PacketView(std::shared_ptr<std::vector<uint8_t>> packet);
-
  private:
   std::forward_list<View> fragments_;
   size_t length_;
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.cc b/vendor_libs/test_vendor_lib/packets/raw_builder.cc
index 794fbb7..2ba2198 100644
--- a/vendor_libs/test_vendor_lib/packets/raw_builder.cc
+++ b/vendor_libs/test_vendor_lib/packets/raw_builder.cc
@@ -16,7 +16,6 @@
 
 #include "raw_builder.h"
 
-#include <base/logging.h>
 #include <algorithm>
 
 using std::vector;
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.h b/vendor_libs/test_vendor_lib/packets/raw_builder.h
index cbc7d6f..82ba885 100644
--- a/vendor_libs/test_vendor_lib/packets/raw_builder.h
+++ b/vendor_libs/test_vendor_lib/packets/raw_builder.h
@@ -19,12 +19,14 @@
 #include <cstdint>
 #include <vector>
 
+#include "hci/address.h"
 #include "packets/packet_builder.h"
-#include "types/address.h"
 
 namespace test_vendor_lib {
 namespace packets {
 
+using ::bluetooth::hci::Address;
+
 class RawBuilder : public PacketBuilder<true> {
  public:
   RawBuilder() = default;
diff --git a/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
index bedc228..c91466b 100644
--- a/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
+++ b/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
@@ -20,8 +20,9 @@
 #include <forward_list>
 #include <memory>
 
-#include "types/address.h"
+#include "hci/address.h"
 
+using ::bluetooth::hci::Address;
 using std::vector;
 
 namespace {
diff --git a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
deleted file mode 100644
index 22ef70f..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright 2018 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 "packets/link_layer/link_layer_packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "link.h"
-#include "packets/link_layer/command_view.h"
-#include "packets/link_layer/disconnect_view.h"
-#include "packets/link_layer/encrypt_connection_view.h"
-#include "packets/link_layer/inquiry_response_view.h"
-#include "packets/link_layer/inquiry_view.h"
-#include "packets/link_layer/io_capability_negative_response_view.h"
-#include "packets/link_layer/io_capability_view.h"
-#include "packets/link_layer/le_advertisement_view.h"
-#include "packets/link_layer/page_response_view.h"
-#include "packets/link_layer/page_view.h"
-#include "packets/link_layer/response_view.h"
-
-#include "base/logging.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-}  // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LinkLayerPacketBuilderTest : public ::testing::Test {
- public:
-  LinkLayerPacketBuilderTest() = default;
-  ~LinkLayerPacketBuilderTest() override = default;
-
-  Address source_{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
-  Address dest_{{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}};
-};
-
-TEST_F(LinkLayerPacketBuilderTest, constructorTest) {
-  uint8_t reason = 0xf2;
-  auto disconnect = DisconnectBuilder::Create(reason);
-  ASSERT_EQ(disconnect->size(), sizeof(reason));
-  auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect), source_, dest_);
-
-  size_t wrapped_size = sizeof(uint8_t) + sizeof(uint32_t) + 2 * sizeof(Address) + sizeof(reason);
-  ASSERT_EQ(wrapped_disconnect->size(), wrapped_size);
-  std::vector<uint8_t> wrapped_vect;
-  std::back_insert_iterator<std::vector<uint8_t>> it(wrapped_vect);
-  wrapped_disconnect->Serialize(it);
-  ASSERT_EQ(wrapped_size, wrapped_vect.size());
-
-  std::vector<uint8_t> hand_wrapped_vect;
-  // Add the size
-  hand_wrapped_vect.push_back(sizeof(uint8_t) + 2 * sizeof(Address) + sizeof(reason));
-  hand_wrapped_vect.push_back(0);
-  hand_wrapped_vect.push_back(0);
-  hand_wrapped_vect.push_back(0);
-
-  hand_wrapped_vect.push_back(static_cast<uint8_t>(Link::PacketType::DISCONNECT));
-
-  for (auto byte : source_.address) {
-    hand_wrapped_vect.push_back(byte);
-  }
-  for (auto byte : dest_.address) {
-    hand_wrapped_vect.push_back(byte);
-  }
-  hand_wrapped_vect.push_back(reason);
-  ASSERT_EQ(wrapped_vect, hand_wrapped_vect);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, disconnectTest) {
-  uint8_t reason = 0x32;
-  auto disconnect_builder = DisconnectBuilder::Create(reason);
-  auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_disconnect->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_disconnect->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::DISCONNECT);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  DisconnectView disconnect = DisconnectView::GetDisconnect(view);
-  ASSERT_EQ(disconnect.GetReason(), reason);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, encryptConnectionTest) {
-  std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-  auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
-  auto wrapped_encrypt_connection =
-      LinkLayerPacketBuilder::WrapEncryptConnection(std::move(encrypt_connection_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_encrypt_connection->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_encrypt_connection->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
-  auto key_itr = encrypt_connection.GetKey();
-  ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
-  for (size_t i = 0; i < key.size(); i++) {
-    ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, encryptConnectionResponseTest) {
-  std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-  auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
-  auto wrapped_encrypt_connection_response =
-      LinkLayerPacketBuilder::WrapEncryptConnectionResponse(std::move(encrypt_connection_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_encrypt_connection_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_encrypt_connection_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
-  auto key_itr = encrypt_connection.GetKey();
-  ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
-  for (size_t i = 0; i < key.size(); i++) {
-    ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, inquiryTest) {
-  Inquiry::InquiryType inquiry_type = Inquiry::InquiryType::RSSI;
-  auto inquiry_builder = InquiryBuilder::Create(inquiry_type);
-  auto wrapped_inquiry = LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry_builder), source_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_inquiry->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_inquiry->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
-  ASSERT_EQ(InquiryView::GetInquiry(view).GetType(), inquiry_type);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, standardInquiryResponseTest) {
-  uint8_t mode = 23;
-  ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
-  uint16_t offset = 0x3456;
-  auto inquiry_response_builder = InquiryResponseBuilder::CreateStandard(mode, class_of_device, offset);
-  auto wrapped_inquiry =
-      LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_inquiry->Serialize(it);
-  ASSERT_EQ(packet_ptr->size(), 24u);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_inquiry->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  ASSERT_EQ(view.GetPayload().size(), 7u);
-  InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-  ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::STANDARD);
-  ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
-  ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, rssiInquiryResponseTest) {
-  uint8_t mode = 23;
-  ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
-  uint16_t offset = 0x3456;
-  uint8_t rssi = 0x78;
-  auto inquiry_response_builder = InquiryResponseBuilder::CreateRssi(mode, class_of_device, offset, rssi);
-  auto wrapped_inquiry =
-      LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_inquiry->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_inquiry->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-  ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::RSSI);
-  ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
-  ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-  ASSERT_EQ(inquiry_response.GetRssi(), rssi);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, extendedInquiryResponseTest) {
-  uint8_t mode = 23;
-  ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
-  uint16_t offset = 0x3456;
-  uint8_t rssi = 0x78;
-  auto inquiry_response_builder = InquiryResponseBuilder::CreateExtended(mode, class_of_device, offset, rssi, count);
-  auto wrapped_inquiry =
-      LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_inquiry->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_inquiry->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-  ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::EXTENDED);
-  ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
-  ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
-  ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-  ASSERT_EQ(inquiry_response.GetRssi(), rssi);
-  auto ext_it = inquiry_response.GetExtendedData();
-  ASSERT_EQ(ext_it.NumBytesRemaining(), count.size());
-  for (size_t i = 0; i < count.size(); i++) {
-    ASSERT_EQ(count[i], *(ext_it++));
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityRequestTest) {
-  uint8_t io_cap = 0x2;
-  uint8_t oob_data_present = 0x1;
-  uint8_t authentication_requirements = 0x5;
-  auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
-  auto wrapped_io_capability_request =
-      LinkLayerPacketBuilder::WrapIoCapabilityRequest(std::move(io_capability_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_io_capability_request->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_io_capability_request->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_REQUEST);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
-  ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
-  ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
-  ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityResponseTest) {
-  uint8_t io_cap = 0x2;
-  uint8_t oob_data_present = 0x1;
-  uint8_t authentication_requirements = 0x5;
-  auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
-  auto wrapped_io_capability_response =
-      LinkLayerPacketBuilder::WrapIoCapabilityResponse(std::move(io_capability_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_io_capability_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_io_capability_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
-  ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
-  ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
-  ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityNegativeResponseTest) {
-  uint8_t reason = 23;
-  auto io_capability_negative_response_builder = IoCapabilityNegativeResponseBuilder::Create(reason);
-  auto wrapped_io_capability_negative_response = LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
-      std::move(io_capability_negative_response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_io_capability_negative_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_io_capability_negative_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  IoCapabilityNegativeResponseView io_capability_negative_response =
-      IoCapabilityNegativeResponseView::GetIoCapabilityNegativeResponse(view);
-  ASSERT_EQ(io_capability_negative_response.GetReason(), reason);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, pageTest) {
-  uint8_t allow_role_switch = 1;
-  ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
-  auto page_builder = PageBuilder::Create(class_of_device, allow_role_switch);
-  auto wrapped_page = LinkLayerPacketBuilder::WrapPage(std::move(page_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_page->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_page->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::PAGE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  PageView page = PageView::GetPage(view);
-  ASSERT_EQ(page.GetAllowRoleSwitch(), allow_role_switch);
-  ASSERT_EQ(page.GetClassOfDevice(), class_of_device);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, pageResponseTest) {
-  uint8_t try_role_switch = 2;
-  auto page_response_builder = PageResponseBuilder::Create(try_role_switch);
-  auto wrapped_page_response =
-      LinkLayerPacketBuilder::WrapPageResponse(std::move(page_response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_page_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_page_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::PAGE_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  PageResponseView page_response = PageResponseView::GetPageResponse(view);
-  ASSERT_EQ(page_response.GetTryRoleSwitch(), try_role_switch);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, responseTest) {
-  uint16_t opcode = 0x1234;
-  std::vector<uint64_t> data{
-      0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303,
-      0x7464544434241404, 0x7565554535251505, 0x7666564636261606, 0x7767574737271707,
-      0x7868584838281808, 0x7969594939291909, 0x7a6a5a4a3a2a1a0a, 0x7b6b5b4b3b2b1b0b,
-      0x7c6c5c4c3c2c1c0c, 0x7d6d5d4d3d2d1d0d, 0x7e6e5e4e3e2e1e0e, 0x7f6f5f4f3f2f1f0f,
-  };
-  auto response_builder = ResponseBuilder::Create(opcode, data);
-  auto wrapped_response = LinkLayerPacketBuilder::WrapResponse(std::move(response_builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  ResponseView response = ResponseView::GetResponse(view);
-  ASSERT_EQ(opcode, response.GetOpcode());
-  auto data_it = response.GetResponseData();
-  ASSERT_EQ(data.size(), data_it.NumBytesRemaining() / sizeof(uint64_t));
-  ASSERT_EQ(0u, data_it.NumBytesRemaining() % sizeof(uint64_t));
-  for (size_t i = 0; i < data.size(); i++) {
-    ASSERT_EQ(data[i], data_it.extract<uint64_t>());
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapAclTest) {
-  std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
-  View count_view(count_shared, 0, count_shared->size());
-  PacketView<true> count_packet_view({count_view});
-  auto builder = ViewForwarderBuilder::Create(count_packet_view);
-  auto wrapped_acl = LinkLayerPacketBuilder::WrapAcl(std::move(builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_acl->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_acl->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::ACL);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  auto acl_view = view.GetPayload();
-  ASSERT_EQ(acl_view.size(), count_view.size());
-  for (size_t i = 0; i < count_view.size(); i++) {
-    ASSERT_EQ(acl_view[i], count_view[i]);
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapCommandTest) {
-  uint16_t opcode = 0x0102;
-  std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
-  View count_view(count_shared, 0, count_shared->size());
-  PacketView<true> args({count_view});
-  auto builder = CommandBuilder::Create(opcode, args);
-  auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_command->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_command->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::COMMAND);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  auto command_view = CommandView::GetCommand(view);
-  ASSERT_EQ(opcode, command_view.GetOpcode());
-  auto args_itr = command_view.GetData();
-  ASSERT_EQ(args_itr.NumBytesRemaining(), count.size());
-  for (size_t i = 0; i < count.size(); i++) {
-    ASSERT_EQ(*args_itr++, count[i]);
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeAdvertisementTest) {
-  LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::RANDOM;
-  LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::ADV_NONCONN_IND;
-  auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
-  auto wrapped_le_advertisement = LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(builder), source_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_le_advertisement->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_le_advertisement->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::LE_ADVERTISEMENT);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
-  LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
-  ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
-  ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
-  auto le_advertisement_itr = le_advertisement_view.GetData();
-  ASSERT_EQ(le_advertisement_itr.NumBytesRemaining(), count.size());
-  for (size_t i = 0; i < count.size(); i++) {
-    ASSERT_EQ(*(le_advertisement_itr++), count[i]);
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeScanTest) {
-  auto le_scan = LinkLayerPacketBuilder::WrapLeScan(source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  le_scan->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), le_scan->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  auto le_scan_view = view.GetPayload();
-  ASSERT_EQ(0u, le_scan_view.size());
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeScanResponseTest) {
-  LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::PUBLIC_IDENTITY;
-  LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::SCAN_RESPONSE;
-  auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
-  auto wrapped_scan_response = LinkLayerPacketBuilder::WrapLeScanResponse(std::move(builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_scan_response->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_scan_response->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN_RESPONSE);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
-  ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
-  ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
-  auto scan_response_itr = le_advertisement_view.GetData();
-  ASSERT_EQ(scan_response_itr.NumBytesRemaining(), count.size());
-  for (size_t i = 0; i < count.size(); i++) {
-    ASSERT_EQ((*scan_response_itr++), count[i]);
-  }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapScoTest) {
-  std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
-  View count_view(count_shared, 0, count_shared->size());
-  PacketView<true> count_packet_view({count_view});
-  auto builder = ViewForwarderBuilder::Create(count_packet_view);
-  auto wrapped_sco = LinkLayerPacketBuilder::WrapSco(std::move(builder), source_, dest_);
-  std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-  std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-  wrapped_sco->Serialize(it);
-
-  LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
-  ASSERT_EQ(view.size(), wrapped_sco->size());
-  ASSERT_EQ(view.GetType(), Link::PacketType::SCO);
-  ASSERT_EQ(source_, view.GetSourceAddress());
-  ASSERT_EQ(dest_, view.GetDestinationAddress());
-  auto sco_view = view.GetPayload();
-  ASSERT_EQ(sco_view.size(), count.size());
-  for (size_t i = 0; i < count.size(); i++) {
-    ASSERT_EQ(sco_view[i], count[i]);
-  }
-}
-
-}  // namespace packets
-}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
index 6fab56d..a2b3569 100644
--- a/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
+++ b/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
@@ -65,8 +65,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<little_endian>::insert(signature_, it);
     PacketBuilder<little_endian>::insert(byte_, it);
     PacketBuilder<little_endian>::insert(two_bytes_, it);
@@ -104,7 +103,9 @@
   }
   ~VectorBuilder() override = default;
 
-  size_t size() const override { return vect_.size() * sizeof(T); }
+  size_t size() const override {
+    return vect_.size() * sizeof(T);
+  }
 
   virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
     std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
@@ -114,8 +115,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<true>::insert_vector(vect_, it);
   }
 
@@ -133,7 +133,9 @@
   }
   ~InsertElementsBuilder() override = default;
 
-  size_t size() const override { return vect_.size() * sizeof(T); }
+  size_t size() const override {
+    return vect_.size() * sizeof(T);
+  }
 
   virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
     std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
@@ -143,8 +145,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     for (T elem : vect_) {
       PacketBuilder<true>::insert(elem, it);
     }
@@ -211,8 +212,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<true>::insert(level_, it);
     if (payload_) {
       payload_->Serialize(it);
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
index b234c20..11891c6 100644
--- a/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
+++ b/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
@@ -20,8 +20,9 @@
 #include <forward_list>
 #include <memory>
 
-#include "types/address.h"
+#include "hci/address.h"
 
+using ::bluetooth::hci::Address;
 using std::vector;
 
 namespace {
@@ -58,7 +59,9 @@
     packet = std::shared_ptr<T>(new T({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())}));
   }
 
-  void TearDown() override { packet.reset(); }
+  void TearDown() override {
+    packet.reset();
+  }
 
   std::shared_ptr<T> packet;
 };
diff --git a/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
index a179b8b..8e69f9f 100644
--- a/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
+++ b/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
@@ -20,8 +20,9 @@
 #include <forward_list>
 #include <memory>
 
-#include "types/address.h"
+#include "hci/address.h"
 
+using ::bluetooth::hci::Address;
 using std::vector;
 
 namespace {
diff --git a/vendor_libs/test_vendor_lib/packets/view.cc b/vendor_libs/test_vendor_lib/packets/view.cc
index 7dbd8bd..a358169 100644
--- a/vendor_libs/test_vendor_lib/packets/view.cc
+++ b/vendor_libs/test_vendor_lib/packets/view.cc
@@ -16,7 +16,7 @@
 
 #include "view.h"
 
-#include <base/logging.h>
+#include "os/log.h"
 
 namespace test_vendor_lib {
 namespace packets {
@@ -33,7 +33,7 @@
 }
 
 uint8_t View::operator[](size_t i) const {
-  CHECK(i + begin_ < end_) << "Out of bounds access at " << i;
+  ASSERT_LOG(i + begin_ < end_, "Out of bounds access at %d", static_cast<int>(i));
   return data_->operator[](i + begin_);
 }
 
diff --git a/vendor_libs/test_vendor_lib/scripts/simple_stack.py b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
index 4f42bf2..95d973a 100644
--- a/vendor_libs/test_vendor_lib/scripts/simple_stack.py
+++ b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
@@ -146,7 +146,7 @@
 
   def receive_response(self):
     ready_to_read, ready_to_write, in_error = \
-               select.select(
+               select(
                   [ self._connection._socket ],
                   [ ],
                   [ self._connection._socket ],
diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py
index 15f5f1f..447130b 100644
--- a/vendor_libs/test_vendor_lib/scripts/test_channel.py
+++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -208,6 +208,12 @@
     """
     self._test_channel.send_command('set', args.split())
 
+  def do_set_device_address(self, args):
+    """Arguments: dev_num addr Set the address of device dev_num equal to addr.
+
+    """
+    self._test_channel.send_command('set_device_address', args.split())
+
   def do_list(self, args):
     """Arguments: [dev_num [attr]] List the devices from the controller, optionally filtered by device and attr.
 
diff --git a/vendor_libs/test_vendor_lib/test/iterator_test.cc b/vendor_libs/test_vendor_lib/test/iterator_test.cc
index b65b60f..0e7b67c 100644
--- a/vendor_libs/test_vendor_lib/test/iterator_test.cc
+++ b/vendor_libs/test_vendor_lib/test/iterator_test.cc
@@ -52,7 +52,9 @@
     packet = TestPacket::make_new_packet(complete_l2cap_packet);
   }
 
-  void TearDown() override { packet.reset(); }
+  void TearDown() override {
+    packet.reset();
+  }
 
   std::shared_ptr<TestPacket> packet;
 };
diff --git a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
index 0ddd2fc..5b4ee49 100644
--- a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
+++ b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
@@ -27,11 +27,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "include/link.h"
 #include "model/setup/async_manager.h"
 #include "packets/link_layer/command_view.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
 
 std::vector<uint8_t> count = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
@@ -185,14 +182,7 @@
 
   LinkLayerPacketView NextPacket() {
     std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
-    View count_view(count_shared, 0, count_shared->size());
-    PacketView<true> args({count_view});
-    auto builder = CommandBuilder::Create(packet_id_++, args);
-    auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
-    std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
-    std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
-    wrapped_command->Serialize(it);
-    LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+    LinkLayerPacketView view = LinkLayerPacketView::Create(count_shared);
     return view;
   }
 
diff --git a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
index 6fab56d..a2b3569 100644
--- a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
+++ b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
@@ -65,8 +65,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<little_endian>::insert(signature_, it);
     PacketBuilder<little_endian>::insert(byte_, it);
     PacketBuilder<little_endian>::insert(two_bytes_, it);
@@ -104,7 +103,9 @@
   }
   ~VectorBuilder() override = default;
 
-  size_t size() const override { return vect_.size() * sizeof(T); }
+  size_t size() const override {
+    return vect_.size() * sizeof(T);
+  }
 
   virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
     std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
@@ -114,8 +115,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<true>::insert_vector(vect_, it);
   }
 
@@ -133,7 +133,9 @@
   }
   ~InsertElementsBuilder() override = default;
 
-  size_t size() const override { return vect_.size() * sizeof(T); }
+  size_t size() const override {
+    return vect_.size() * sizeof(T);
+  }
 
   virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
     std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
@@ -143,8 +145,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     for (T elem : vect_) {
       PacketBuilder<true>::insert(elem, it);
     }
@@ -211,8 +212,7 @@
     return packet;
   }
 
-  void Serialize(
-      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+  void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
     PacketBuilder<true>::insert(level_, it);
     if (payload_) {
       payload_->Serialize(it);
diff --git a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
index 7481235..c67c95e 100644
--- a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
@@ -83,33 +83,6 @@
     for (int i = 0; i < payload_size; ++i) EXPECT_EQ(packet[4 + i], received_payload[i + 1]);
   }
 
-  void CheckedSendEvent(std::unique_ptr<EventPacket> event) {
-    const vector<uint8_t> expected_payload = event->GetPayload();
-    auto expected_size = event->GetPacketSize();
-    auto expected_code = event->GetEventCode();
-    auto expected_payload_size = event->GetPayloadSize();
-
-    EXPECT_TRUE(packet_stream_.SendEvent(std::move(event), socketpair_fds_[0]));
-
-    // Read the packet sent by |packet_stream_|.
-    uint8_t event_header[2];
-    read(socketpair_fds_[1], event_header, 2);
-
-    uint8_t return_parameters_size;
-    read(socketpair_fds_[1], &return_parameters_size, 1);
-
-    uint8_t return_parameters[return_parameters_size];
-    read(socketpair_fds_[1], return_parameters, sizeof(return_parameters));
-
-    // Validate the packet by checking that it's the
-    // appropriate size and then checking each byte.
-    EXPECT_EQ(expected_size, sizeof(event_header) + return_parameters_size + 1);
-    EXPECT_EQ(DATA_TYPE_EVENT, event_header[0]);
-    EXPECT_EQ(expected_code, event_header[1]);
-    EXPECT_EQ(expected_payload_size, static_cast<size_t>(return_parameters_size) + 1);
-    for (int i = 0; i < return_parameters_size; ++i) EXPECT_EQ(expected_payload[i + 1], return_parameters[i]);
-  }
-
  protected:
   PacketStream packet_stream_;
 
@@ -141,9 +114,4 @@
   CheckedReceiveCommand(large_payload, HCI_RESET);
 }
 
-TEST_F(PacketStreamTest, SendEvent) {
-  const vector<uint8_t> return_parameters = {0};
-  CheckedSendEvent(EventPacket::CreateCommandCompleteEvent(HCI_RESET, return_parameters));
-}
-
 }  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
index 13aab3c..9c19c4f 100644
--- a/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
@@ -16,22 +16,20 @@
  *
  ******************************************************************************/
 
-#include <gtest/gtest.h>
-#include <string>
-#include <vector>
-using std::vector;
-
 #include "model/controller/security_manager.h"
 
+#include <gtest/gtest.h>
+#include <array>
+#include <string>
+
 namespace {
 const std::string kTestAddr1 = "12:34:56:78:9a:bc";
 const std::string kTestAddr2 = "cb:a9:87:65:43:21";
 const std::string kTestAddr3 = "cb:a9:56:78:9a:bc";
 const std::string kTestAddr4 = "12:34:56:78:9a:bc";
-const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
-const vector<uint8_t> kTestKey = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
-                                  0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
+const std::array<uint8_t, 16> kTestKey = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+                                          0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+                                          0x0d, 0x0e, 0x0f, 0x10};
 }  // namespace
 
 namespace test_vendor_lib {
diff --git a/vendor_libs/test_vendor_lib/types/Android.bp b/vendor_libs/test_vendor_lib/types/Android.bp
index 07198e9..7e1193c 100644
--- a/vendor_libs/test_vendor_lib/types/Android.bp
+++ b/vendor_libs/test_vendor_lib/types/Android.bp
@@ -16,8 +16,6 @@
     ],
     host_supported: true,
     srcs: [
-        "class_of_device.cc",
-        "address.cc",
         "bluetooth/uuid.cc",
     ],
     header_libs: ["libbt-rootcanal-types-header"],
@@ -31,8 +29,6 @@
     defaults: ["fluoride_defaults"],
     host_supported: true,
     srcs: [
-        "test/class_of_device_unittest.cc",
-        "test/address_unittest.cc",
         "test/bluetooth/uuid_unittest.cc",
     ],
     static_libs: [
diff --git a/vendor_libs/test_vendor_lib/types/address.cc b/vendor_libs/test_vendor_lib/types/address.cc
deleted file mode 100644
index b3c1db4..0000000
--- a/vendor_libs/test_vendor_lib/types/address.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2017 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 "address.h"
-
-#include <base/strings/string_split.h>
-#include <base/strings/stringprintf.h>
-#include <stdint.h>
-#include <algorithm>
-#include <vector>
-
-static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
-
-const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
-const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
-
-Address::Address(const uint8_t (&addr)[6]) {
-  std::copy(addr, addr + kLength, address);
-};
-
-std::string Address::ToString() const {
-  return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1],
-                            address[0]);
-}
-
-bool Address::FromString(const std::string& from, Address& to) {
-  Address new_addr;
-  if (from.length() != 17) return false;
-
-  std::vector<std::string> byte_tokens = base::SplitString(from, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  if (byte_tokens.size() != 6) return false;
-
-  for (int i = 0; i < 6; i++) {
-    const auto& token = byte_tokens[i];
-
-    if (token.length() != 2) return false;
-
-    char* temp = nullptr;
-    new_addr.address[5 - i] = strtol(token.c_str(), &temp, 16);
-    if (*temp != '\0') return false;
-  }
-
-  to = new_addr;
-  return true;
-}
-
-size_t Address::FromOctets(const uint8_t* from) {
-  std::copy(from, from + kLength, address);
-  return kLength;
-};
-
-bool Address::IsValidAddress(const std::string& address) {
-  Address tmp;
-  return Address::FromString(address, tmp);
-}
diff --git a/vendor_libs/test_vendor_lib/types/address.h b/vendor_libs/test_vendor_lib/types/address.h
deleted file mode 100644
index 1aa8c97..0000000
--- a/vendor_libs/test_vendor_lib/types/address.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2017 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>
-
-/** Bluetooth Address */
-class Address final {
- public:
-  static constexpr unsigned int kLength = 6;
-
-  uint8_t address[kLength];
-
-  Address() = default;
-  Address(const uint8_t (&addr)[6]);
-
-  bool operator<(const Address& rhs) const {
-    return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
-  }
-  bool operator==(const Address& rhs) const {
-    return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
-  }
-  bool operator>(const Address& rhs) const {
-    return (rhs < *this);
-  }
-  bool operator<=(const Address& rhs) const {
-    return !(*this > rhs);
-  }
-  bool operator>=(const Address& rhs) const {
-    return !(*this < rhs);
-  }
-  bool operator!=(const Address& rhs) const {
-    return !(*this == rhs);
-  }
-
-  bool IsEmpty() const {
-    return *this == kEmpty;
-  }
-
-  std::string ToString() const;
-
-  // Converts |string| to Address and places it in |to|. If |from| does
-  // not represent a Bluetooth address, |to| is not modified and this function
-  // returns false. Otherwise, it returns true.
-  static bool FromString(const std::string& from, Address& to);
-
-  // Copies |from| raw Bluetooth address octets to the local object.
-  // Returns the number of copied octets - should be always Address::kLength
-  size_t FromOctets(const uint8_t* from);
-
-  static bool IsValidAddress(const std::string& address);
-
-  static const Address kEmpty;  // 00:00:00:00:00:00
-  static const Address kAny;    // FF:FF:FF:FF:FF:FF
-};
-
-inline std::ostream& operator<<(std::ostream& os, const Address& a) {
-  os << a.ToString();
-  return os;
-}
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.cc b/vendor_libs/test_vendor_lib/types/class_of_device.cc
deleted file mode 100644
index c5f1c3f..0000000
--- a/vendor_libs/test_vendor_lib/types/class_of_device.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2018 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 "class_of_device.h"
-
-#include <base/strings/string_split.h>
-#include <base/strings/stringprintf.h>
-#include <stdint.h>
-#include <algorithm>
-#include <vector>
-
-static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
-
-ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
-  std::copy(class_of_device, class_of_device + kLength, cod);
-};
-
-std::string ClassOfDevice::ToString() const {
-  return base::StringPrintf("%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f,
-                            cod[0]);
-}
-
-bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
-  ClassOfDevice new_cod;
-  if (from.length() != 8) return false;
-
-  std::vector<std::string> byte_tokens = base::SplitString(from, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  if (byte_tokens.size() != 3) return false;
-  if (byte_tokens[0].length() != 3) return false;
-  if (byte_tokens[1].length() != 1) return false;
-  if (byte_tokens[2].length() != 2) return false;
-
-  uint16_t values[3];
-
-  for (size_t i = 0; i < kLength; i++) {
-    const auto& token = byte_tokens[i];
-
-    char* temp = nullptr;
-    values[i] = strtol(token.c_str(), &temp, 16);
-    if (*temp != '\0') return false;
-  }
-
-  new_cod.cod[0] = values[2];
-  new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
-  new_cod.cod[2] = values[0] >> 4;
-
-  to = new_cod;
-  return true;
-}
-
-size_t ClassOfDevice::FromOctets(const uint8_t* from) {
-  std::copy(from, from + kLength, cod);
-  return kLength;
-};
-
-bool ClassOfDevice::IsValid(const std::string& cod) {
-  ClassOfDevice tmp;
-  return ClassOfDevice::FromString(cod, tmp);
-}
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.h b/vendor_libs/test_vendor_lib/types/class_of_device.h
deleted file mode 100644
index 8c2ab37..0000000
--- a/vendor_libs/test_vendor_lib/types/class_of_device.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2018 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>
-
-/** Bluetooth Class of Device */
-class ClassOfDevice final {
- public:
-  static constexpr unsigned int kLength = 3;
-
-  uint8_t cod[kLength];
-
-  ClassOfDevice() = default;
-  ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
-
-  bool operator==(const ClassOfDevice& rhs) const {
-    return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
-  }
-
-  std::string ToString() const;
-
-  // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
-  // not represent a Class of Device, |to| is not modified and this function
-  // returns false. Otherwise, it returns true.
-  static bool FromString(const std::string& from, ClassOfDevice& to);
-
-  // Copies |from| raw Class of Device octets to the local object.
-  // Returns the number of copied octets (always ClassOfDevice::kLength)
-  size_t FromOctets(const uint8_t* from);
-
-  static bool IsValid(const std::string& class_of_device);
-};
-
-inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
-  os << c.ToString();
-  return os;
-}
diff --git a/vendor_libs/test_vendor_lib/types/test/address_unittest.cc b/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
deleted file mode 100644
index 65fd26d..0000000
--- a/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2017 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 <gtest/gtest.h>
-
-#include "address.h"
-
-static const char* test_addr = "bc:9a:78:56:34:12";
-static const char* test_addr2 = "21:43:65:87:a9:cb";
-
-TEST(AddressUnittest, test_constructor_array) {
-  Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
-
-  ASSERT_EQ(0x12, bdaddr.address[0]);
-  ASSERT_EQ(0x34, bdaddr.address[1]);
-  ASSERT_EQ(0x56, bdaddr.address[2]);
-  ASSERT_EQ(0x78, bdaddr.address[3]);
-  ASSERT_EQ(0x9A, bdaddr.address[4]);
-  ASSERT_EQ(0xBC, bdaddr.address[5]);
-
-  std::string ret = bdaddr.ToString();
-
-  ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_is_empty) {
-  Address empty;
-  Address::FromString("00:00:00:00:00:00", empty);
-  ASSERT_TRUE(empty.IsEmpty());
-
-  Address not_empty;
-  Address::FromString("00:00:00:00:00:01", not_empty);
-  ASSERT_FALSE(not_empty.IsEmpty());
-}
-
-TEST(AddressUnittest, test_to_from_str) {
-  Address bdaddr;
-  Address::FromString(test_addr, bdaddr);
-
-  ASSERT_EQ(0x12, bdaddr.address[0]);
-  ASSERT_EQ(0x34, bdaddr.address[1]);
-  ASSERT_EQ(0x56, bdaddr.address[2]);
-  ASSERT_EQ(0x78, bdaddr.address[3]);
-  ASSERT_EQ(0x9A, bdaddr.address[4]);
-  ASSERT_EQ(0xBC, bdaddr.address[5]);
-
-  std::string ret = bdaddr.ToString();
-
-  ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_from_octets) {
-  static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
-
-  Address bdaddr;
-  size_t expected_result = Address::kLength;
-  ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
-
-  ASSERT_EQ(0x12, bdaddr.address[0]);
-  ASSERT_EQ(0x34, bdaddr.address[1]);
-  ASSERT_EQ(0x56, bdaddr.address[2]);
-  ASSERT_EQ(0x78, bdaddr.address[3]);
-  ASSERT_EQ(0x9A, bdaddr.address[4]);
-  ASSERT_EQ(0xBC, bdaddr.address[5]);
-
-  std::string ret = bdaddr.ToString();
-
-  ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressTest, test_equals) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address bdaddr3;
-  Address::FromString(test_addr, bdaddr1);
-  Address::FromString(test_addr, bdaddr2);
-  EXPECT_TRUE(bdaddr1 == bdaddr2);
-  EXPECT_FALSE(bdaddr1 != bdaddr2);
-  EXPECT_TRUE(bdaddr1 == bdaddr1);
-  EXPECT_FALSE(bdaddr1 != bdaddr1);
-
-  Address::FromString(test_addr2, bdaddr3);
-  EXPECT_FALSE(bdaddr2 == bdaddr3);
-  EXPECT_TRUE(bdaddr2 != bdaddr3);
-}
-
-TEST(AddressTest, test_less_than) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address bdaddr3;
-  Address::FromString(test_addr, bdaddr1);
-  Address::FromString(test_addr, bdaddr2);
-  EXPECT_FALSE(bdaddr1 < bdaddr2);
-  EXPECT_FALSE(bdaddr1 < bdaddr1);
-
-  Address::FromString(test_addr2, bdaddr3);
-  EXPECT_TRUE(bdaddr2 < bdaddr3);
-  EXPECT_FALSE(bdaddr3 < bdaddr2);
-}
-
-TEST(AddressTest, test_more_than) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address bdaddr3;
-  Address::FromString(test_addr, bdaddr1);
-  Address::FromString(test_addr, bdaddr2);
-  EXPECT_FALSE(bdaddr1 > bdaddr2);
-  EXPECT_FALSE(bdaddr1 > bdaddr1);
-
-  Address::FromString(test_addr2, bdaddr3);
-  EXPECT_FALSE(bdaddr2 > bdaddr3);
-  EXPECT_TRUE(bdaddr3 > bdaddr2);
-}
-
-TEST(AddressTest, test_less_than_or_equal) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address bdaddr3;
-  Address::FromString(test_addr, bdaddr1);
-  Address::FromString(test_addr, bdaddr2);
-  EXPECT_TRUE(bdaddr1 <= bdaddr2);
-  EXPECT_TRUE(bdaddr1 <= bdaddr1);
-
-  Address::FromString(test_addr2, bdaddr3);
-  EXPECT_TRUE(bdaddr2 <= bdaddr3);
-  EXPECT_FALSE(bdaddr3 <= bdaddr2);
-}
-
-TEST(AddressTest, test_more_than_or_equal) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address bdaddr3;
-  Address::FromString(test_addr, bdaddr1);
-  Address::FromString(test_addr, bdaddr2);
-  EXPECT_TRUE(bdaddr1 >= bdaddr2);
-  EXPECT_TRUE(bdaddr1 >= bdaddr1);
-
-  Address::FromString(test_addr2, bdaddr3);
-  EXPECT_FALSE(bdaddr2 >= bdaddr3);
-  EXPECT_TRUE(bdaddr3 >= bdaddr2);
-}
-
-TEST(AddressTest, test_copy) {
-  Address bdaddr1;
-  Address bdaddr2;
-  Address::FromString(test_addr, bdaddr1);
-  bdaddr2 = bdaddr1;
-
-  EXPECT_TRUE(bdaddr1 == bdaddr2);
-}
-
-TEST(AddressTest, IsValidAddress) {
-  EXPECT_FALSE(Address::IsValidAddress(""));
-  EXPECT_FALSE(Address::IsValidAddress("000000000000"));
-  EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
-  EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
-  EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
-  EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
-  EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
-  EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
-}
-
-TEST(AddressTest, BdAddrFromString) {
-  Address addr;
-  memset(&addr, 0, sizeof(addr));
-
-  EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
-  const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
-  EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
-
-  EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
-  const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
-  EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
-}
-
-TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
-  std::string address = "c1:c2:c3:d1:d2:d3";
-  Address addr;
-
-  EXPECT_TRUE(Address::FromString(address, addr));
-  EXPECT_EQ(addr.ToString(), address);
-}
diff --git a/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc b/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
deleted file mode 100644
index 5d652a5..0000000
--- a/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/******************************************************************************
- *
- *  Copyright 2018 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 <gtest/gtest.h>
-
-#include "class_of_device.h"
-
-static const char* test_class = "efc-d-ab";
-static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
-
-TEST(ClassOfDeviceUnittest, test_constructor_array) {
-  ClassOfDevice cod(test_bytes);
-
-  ASSERT_EQ(test_bytes[0], cod.cod[0]);
-  ASSERT_EQ(test_bytes[1], cod.cod[1]);
-  ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
-  std::string ret = cod.ToString();
-
-  ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_to_from_str) {
-  ClassOfDevice cod;
-  ClassOfDevice::FromString(test_class, cod);
-
-  ASSERT_EQ(test_bytes[0], cod.cod[0]);
-  ASSERT_EQ(test_bytes[1], cod.cod[1]);
-  ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
-  std::string ret = cod.ToString();
-
-  ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_from_octets) {
-  ClassOfDevice cod;
-  size_t expected_result = ClassOfDevice::kLength;
-  ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
-
-  ASSERT_EQ(test_bytes[0], cod.cod[0]);
-  ASSERT_EQ(test_bytes[1], cod.cod[1]);
-  ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
-  std::string ret = cod.ToString();
-
-  ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceTest, test_copy) {
-  ClassOfDevice cod1;
-  ClassOfDevice cod2;
-  ClassOfDevice::FromString(test_class, cod1);
-  cod2 = cod1;
-
-  ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
-  ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
-  ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
-}
-
-TEST(ClassOfDeviceTest, IsValid) {
-  EXPECT_FALSE(ClassOfDevice::IsValid(""));
-  EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
-  EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
-  EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
-  EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
-  EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
-  EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
-}
-
-TEST(ClassOfDeviceTest, classOfDeviceFromString) {
-  ClassOfDevice cod;
-
-  EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
-  const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
-  EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
-
-  EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
-  const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
-  EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
-}