Merge "audiohal: Do not log if EINVAL is received from get_presentation_position"
diff --git a/audio/common/2.0/default/HidlUtils.cpp b/audio/common/2.0/default/HidlUtils.cpp
index f25fc5c..b1bff00 100644
--- a/audio/common/2.0/default/HidlUtils.cpp
+++ b/audio/common/2.0/default/HidlUtils.cpp
@@ -114,6 +114,9 @@
     halOffload->duration_us = offload.durationMicroseconds;
     halOffload->has_video = offload.hasVideo;
     halOffload->is_streaming = offload.isStreaming;
+    halOffload->bit_width = offload.bitWidth;
+    halOffload->offload_buffer_size = offload.bufferSize;
+    halOffload->usage = static_cast<audio_usage_t>(offload.usage);
 }
 
 void HidlUtils::audioPortConfigFromHal(
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal
index 4e969a7..d1674e4 100644
--- a/audio/common/2.0/types.hal
+++ b/audio/common/2.0/types.hal
@@ -107,7 +107,7 @@
     ACCESSIBILITY    = 10, // For accessibility talk back prompts
     REROUTING        = 11, // For dynamic policy output mixes
     PATCH            = 12, // For internal audio flinger tracks.  Fixed volume
-    PUBLIC_CNT       = TTS + 1,
+    PUBLIC_CNT       = ACCESSIBILITY + 1,
     // Number of streams considered by audio policy for volume and routing
     FOR_POLICY_CNT   = PATCH,
     CNT              = PATCH + 1
@@ -215,6 +215,25 @@
     // IEC61937 is encoded audio wrapped in 16-bit PCM.
     IEC61937            = 0x0D000000UL,
     DOLBY_TRUEHD        = 0x0E000000UL,
+    EVRC                = 0x10000000UL,
+    EVRCB               = 0x11000000UL,
+    EVRCWB              = 0x12000000UL,
+    EVRCNW              = 0x13000000UL,
+    AAC_ADIF            = 0x14000000UL,
+    WMA                 = 0x15000000UL,
+    WMA_PRO             = 0x16000000UL,
+    AMR_WB_PLUS         = 0x17000000UL,
+    MP2                 = 0x18000000UL,
+    QCELP               = 0x19000000UL,
+    DSD                 = 0x1A000000UL,
+    FLAC                = 0x1B000000UL,
+    ALAC                = 0x1C000000UL,
+    APE                 = 0x1D000000UL,
+    AAC_ADTS            = 0x1E000000UL,
+    SBC                 = 0x1F000000UL,
+    APTX                = 0x20000000UL,
+    APTX_HD             = 0x21000000UL,
+    LDAC                = 0x22000000UL,
     MAIN_MASK           = 0xFF000000UL, /* Deprecated */
     SUB_MASK            = 0x00FFFFFFUL,
 
@@ -261,7 +280,17 @@
     AAC_ERLC            = (AAC | AAC_SUB_ERLC),
     AAC_LD              = (AAC | AAC_SUB_LD),
     AAC_HE_V2           = (AAC | AAC_SUB_HE_V2),
-    AAC_ELD             = (AAC | AAC_SUB_ELD)
+    AAC_ELD             = (AAC | AAC_SUB_ELD),
+    AAC_ADTS_MAIN       = (AAC_ADTS | AAC_SUB_MAIN),
+    AAC_ADTS_LC         = (AAC_ADTS | AAC_SUB_LC),
+    AAC_ADTS_SSR        = (AAC_ADTS | AAC_SUB_SSR),
+    AAC_ADTS_LTP        = (AAC_ADTS | AAC_SUB_LTP),
+    AAC_ADTS_HE_V1      = (AAC_ADTS | AAC_SUB_HE_V1),
+    AAC_ADTS_SCALABLE   = (AAC_ADTS | AAC_SUB_SCALABLE),
+    AAC_ADTS_ERLC       = (AAC_ADTS | AAC_SUB_ERLC),
+    AAC_ADTS_LD         = (AAC_ADTS | AAC_SUB_LD),
+    AAC_ADTS_HE_V2      = (AAC_ADTS | AAC_SUB_HE_V2),
+    AAC_ADTS_ELD        = (AAC_ADTS | AAC_SUB_ELD)
 };
 
 /*
@@ -344,13 +373,17 @@
 
     OUT_MONO     = OUT_FRONT_LEFT,
     OUT_STEREO   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+    OUT_2POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
     OUT_QUAD     = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
             OUT_BACK_LEFT | OUT_BACK_RIGHT),
     OUT_QUAD_BACK = OUT_QUAD,
     /* like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
     OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
             OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
-    OUT_5POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_BACK_CENTER),
+    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+    OUT_5POINT1   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
             OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
             OUT_BACK_LEFT | OUT_BACK_RIGHT),
     OUT_5POINT1_BACK = OUT_5POINT1,
@@ -358,6 +391,10 @@
     OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
             OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
             OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_BACK_CENTER),
     /* matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
     OUT_7POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
             OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
@@ -394,6 +431,10 @@
     IN_MONO   = IN_FRONT,
     IN_STEREO = (IN_LEFT | IN_RIGHT),
     IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+    IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+    IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+    IN_VOICE_CALL_MONO   = (IN_VOICE_UPLINK_MONO |
+            IN_VOICE_DNLINK_MONO),
     IN_ALL    = (IN_LEFT | IN_RIGHT | IN_FRONT | IN_BACK|
             IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED |
             IN_FRONT_PROCESSED | IN_BACK_PROCESSED|
@@ -491,6 +532,7 @@
     OUT_IP                        = 0x800000,
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     OUT_BUS                       = 0x1000000,
+    OUT_PROXY                     = 0x2000000,
     OUT_DEFAULT                   = BIT_DEFAULT,
     OUT_ALL      = (OUT_EARPIECE |
             OUT_SPEAKER |
@@ -517,6 +559,7 @@
             OUT_SPEAKER_SAFE |
             OUT_IP |
             OUT_BUS |
+            OUT_PROXY |
             OUT_DEFAULT),
     OUT_ALL_A2DP = (OUT_BLUETOOTH_A2DP |
             OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -555,6 +598,7 @@
     IN_IP                    = BIT_IN | 0x80000,
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     IN_BUS                   = BIT_IN | 0x100000,
+    IN_PROXY                 = BIT_IN | 0x1000000,
     IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
 
     IN_ALL     = (IN_COMMUNICATION |
@@ -578,6 +622,7 @@
             IN_LOOPBACK |
             IN_IP |
             IN_BUS |
+            IN_PROXY |
             IN_DEFAULT),
     IN_ALL_SCO = IN_BLUETOOTH_SCO_HEADSET,
     IN_ALL_USB  = (IN_USB_ACCESSORY | IN_USB_DEVICE),
@@ -618,6 +663,8 @@
     SYNC       = 0x200,  // synchronize I/O streams
     IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
                              // data bursts, not PCM.
+    DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
+                             // to pass through compress path for DSP post proc.
 };
 
 /*
@@ -635,6 +682,32 @@
     SYNC       = 0x8,  // synchronize I/O streams
 };
 
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioAttributes.java
+    // TODO: Synchronization should be done automatically by tools
+    UNKNOWN                            = 0,
+    MEDIA                              = 1,
+    VOICE_COMMUNICATION                = 2,
+    VOICE_COMMUNICATION_SIGNALLING     = 3,
+    ALARM                              = 4,
+    NOTIFICATION                       = 5,
+    NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    NOTIFICATION_COMMUNICATION_REQUEST = 7,
+    NOTIFICATION_COMMUNICATION_INSTANT = 8,
+    NOTIFICATION_COMMUNICATION_DELAYED = 9,
+    NOTIFICATION_EVENT                 = 10,
+    ASSISTANCE_ACCESSIBILITY           = 11,
+    ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    ASSISTANCE_SONIFICATION            = 13,
+    GAME                               = 14,
+    VIRTUAL_SOURCE                     = 15,
+
+    CNT,
+    MAX                                = CNT - 1,
+};
+
 /*
  * Additional information about the stream passed to hardware decoders.
  */
@@ -647,6 +720,9 @@
     int64_t durationMicroseconds;  // -1 if unknown
     bool hasVideo;
     bool isStreaming;
+    uint32_t bitWidth;
+    uint32_t bufferSize;
+    AudioUsage usage;
 };
 
 /*
diff --git a/boot/1.0/vts/Android.bp b/boot/1.0/vts/Android.bp
new file mode 100644
index 0000000..7aef46b
--- /dev/null
+++ b/boot/1.0/vts/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+    "*"
+]
diff --git a/boot/1.0/vts/Android.mk b/boot/1.0/vts/Android.mk
index 8a56b27..9b30ef1 100644
--- a/boot/1.0/vts/Android.mk
+++ b/boot/1.0/vts/Android.mk
@@ -77,3 +77,5 @@
 LOCAL_PROTOC_OPTIMIZE_TYPE := full
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/boot/1.0/vts/functional/Android.bp b/boot/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..714a18b
--- /dev/null
+++ b/boot/1.0/vts/functional/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "boot_hidl_hal_test",
+    gtest: true,
+    srcs: ["boot_hidl_hal_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhwbinder",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.boot@1.0",
+    ],
+    static_libs: ["libgtest"],
+    cflags: [
+        "--coverage",
+        "-O0",
+        "-g",
+    ],
+    ldflags: [
+        "--coverage"
+    ]
+}
diff --git a/boot/1.0/vts/functional/Android.mk b/boot/1.0/vts/functional/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/boot_hidl_hal_test.cpp b/boot/1.0/vts/functional/boot_hidl_hal_test.cpp
new file mode 100644
index 0000000..7b002b9
--- /dev/null
+++ b/boot/1.0/vts/functional/boot_hidl_hal_test.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "boot_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <cutils/properties.h>
+
+#include <android/hardware/boot/1.0/IBootControl.h>
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::boot::V1_0::IBootControl;
+using ::android::hardware::boot::V1_0::CommandResult;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::sp;
+
+// The main test class for the Boot HIDL HAL.
+class BootHidlTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    // TODO(b/33385836) Delete copied code
+    bool getStub = false;
+    char getsubProperty[PROPERTY_VALUE_MAX];
+    if (property_get("vts.hidl.get_stub", getsubProperty, "") > 0) {
+      if (!strcmp(getsubProperty, "true") || !strcmp(getsubProperty, "True") ||
+          !strcmp(getsubProperty, "1")) {
+        getStub = true;
+      }
+    }
+    boot = IBootControl::getService("bootctrl", getStub);
+    ASSERT_NE(boot, nullptr);
+    ASSERT_EQ(!getStub, boot->isRemote());
+  }
+
+  virtual void TearDown() override {}
+
+  sp<IBootControl> boot;
+};
+
+auto generate_callback(CommandResult *dest) {
+  return [=](CommandResult cr) { *dest = cr; };
+}
+
+// Sanity check Boot::getNumberSlots().
+TEST_F(BootHidlTest, GetNumberSlots) {
+  uint32_t slots = boot->getNumberSlots();
+  EXPECT_LE((uint32_t)2, slots);
+}
+
+// Sanity check Boot::getCurrentSlot().
+TEST_F(BootHidlTest, GetCurrentSlot) {
+  Slot curSlot = boot->getCurrentSlot();
+  uint32_t slots = boot->getNumberSlots();
+  EXPECT_LT(curSlot, slots);
+}
+
+// Sanity check Boot::markBootSuccessful().
+TEST_F(BootHidlTest, MarkBootSuccessful) {
+  CommandResult cr;
+  Return<void> result = boot->markBootSuccessful(generate_callback(&cr));
+  ASSERT_TRUE(result.getStatus().isOk());
+  if (cr.success) {
+    Slot curSlot = boot->getCurrentSlot();
+    BoolResult ret = boot->isSlotMarkedSuccessful(curSlot);
+    EXPECT_EQ(BoolResult::TRUE, ret);
+  }
+}
+
+// Sanity check Boot::setActiveBootSlot() on good and bad inputs.
+TEST_F(BootHidlTest, SetActiveBootSlot) {
+  for (Slot s = 0; s < 2; s++) {
+    CommandResult cr;
+    Return<void> result = boot->setActiveBootSlot(s, generate_callback(&cr));
+    EXPECT_TRUE(result.getStatus().isOk());
+  }
+  {
+    CommandResult cr;
+    uint32_t slots = boot->getNumberSlots();
+    Return<void> result =
+        boot->setActiveBootSlot(slots, generate_callback(&cr));
+    ASSERT_TRUE(result.getStatus().isOk());
+    EXPECT_EQ(false, cr.success);
+  }
+}
+
+// Sanity check Boot::setSlotAsUnbootable() on good and bad inputs.
+TEST_F(BootHidlTest, SetSlotAsUnbootable) {
+  {
+    CommandResult cr;
+    Slot curSlot = boot->getCurrentSlot();
+    Slot otherSlot = curSlot ? 0 : 1;
+    Return<void> result =
+        boot->setSlotAsUnbootable(otherSlot, generate_callback(&cr));
+    EXPECT_TRUE(result.getStatus().isOk());
+    if (cr.success) {
+      EXPECT_EQ(BoolResult::FALSE, boot->isSlotBootable(otherSlot));
+      boot->setActiveBootSlot(otherSlot, generate_callback(&cr));
+      EXPECT_TRUE(cr.success);
+    }
+  }
+  {
+    CommandResult cr;
+    uint32_t slots = boot->getNumberSlots();
+    Return<void> result =
+        boot->setSlotAsUnbootable(slots, generate_callback(&cr));
+    EXPECT_TRUE(result.getStatus().isOk());
+    EXPECT_EQ(false, cr.success);
+  }
+}
+
+// Sanity check Boot::isSlotBootable() on good and bad inputs.
+TEST_F(BootHidlTest, IsSlotBootable) {
+  for (Slot s = 0; s < 2; s++) {
+    EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotBootable(s));
+  }
+  uint32_t slots = boot->getNumberSlots();
+  EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotBootable(slots));
+}
+
+// Sanity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
+TEST_F(BootHidlTest, IsSlotMarkedSuccessful) {
+  for (Slot s = 0; s < 2; s++) {
+    EXPECT_NE(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(s));
+  }
+  uint32_t slots = boot->getNumberSlots();
+  EXPECT_EQ(BoolResult::INVALID_SLOT, boot->isSlotMarkedSuccessful(slots));
+}
+
+// Sanity check Boot::getSuffix() on good and bad inputs.
+TEST_F(BootHidlTest, GetSuffix) {
+  const char *suffixPtr;
+  auto cb = [&](hidl_string suffix) { suffixPtr = suffix.c_str(); };
+  for (Slot i = 0; i < 2; i++) {
+    CommandResult cr;
+    Return<void> result = boot->getSuffix(i, cb);
+    EXPECT_TRUE(result.getStatus().isOk());
+    char correctSuffix[3];
+    snprintf(correctSuffix, sizeof(correctSuffix), "_%c", 'a' + i);
+    ASSERT_EQ(0, strcmp(suffixPtr, correctSuffix));
+  }
+  {
+    char emptySuffix[] = "";
+    Return<void> result = boot->getSuffix(boot->getNumberSlots(), cb);
+    EXPECT_TRUE(result.getStatus().isOk());
+    ASSERT_EQ(0, strcmp(emptySuffix, suffixPtr));
+  }
+}
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/boot/1.0/vts/functional/vts/Android.mk b/boot/1.0/vts/functional/vts/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/vts/testcases/Android.mk b/boot/1.0/vts/functional/vts/testcases/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/vts/testcases/hal/Android.mk b/boot/1.0/vts/functional/vts/testcases/hal/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/hal/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/vts/testcases/hal/boot/Android.mk b/boot/1.0/vts/functional/vts/testcases/hal/boot/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/hal/boot/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/Android.mk b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/Android.mk b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/Android.mk
new file mode 100644
index 0000000..844b93b
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := HalBootHidlTargetTest
+VTS_CONFIG_SRC_DIR := testcases/hal/boot/hidl/target
+include test/vts/tools/build/Android.host_config.mk
diff --git a/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/AndroidTest.xml b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/AndroidTest.xml
new file mode 100644
index 0000000..6c7809c
--- /dev/null
+++ b/boot/1.0/vts/functional/vts/testcases/hal/boot/hidl/target/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS Boot HIDL HAL's target-side test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="push-group" value="HidlHalTest.push" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="HalBootHidlTargetTest"/>
+        <option name="binary-test-sources" value="
+            _32bit::DATA/nativetest/boot_hidl_hal_test/boot_hidl_hal_test,
+            _64bit::DATA/nativetest64/boot_hidl_hal_test/boot_hidl_hal_test,
+            "/>
+        <option name="binary-test-type" value="gtest" />
+        <option name="test-timeout" value="1m" />
+    </test>
+</configuration>
diff --git a/boot/Android.bp b/boot/Android.bp
index bbb3e4b..67af5bb 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -1,4 +1,6 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "1.0",
+    "1.0/vts",
+    "1.0/vts/functional",
 ]
diff --git a/boot/Android.mk b/boot/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/boot/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index f29b916..62bc840 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -382,7 +382,7 @@
      *        override the one in the profile. empty string indicates no APN overrride.
      * @param user is the username for APN, or empty string
      * @param password is the password for APN, or empty string
-     * @param authType is the PAP / CHAP auth type. Values:
+     * @param authType is the PAP / CHAP auth type.
      * @param protocol is the connection type to request must be one of the
      *        PDP_type values in TS 27.007 section 10.1.1.
      *        For example, "IP", "IPV6", "IPV4V6", or "PPP".
@@ -1272,7 +1272,7 @@
      * @param protocol is the connection type to request must be one of the
      *        PDP_type values in TS 27.007 section 10.1.1.
      *        For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     * @param authType is the PAP / CHAP auth type. Values:
+     * @param authType is the PAP / CHAP auth type.
      * @param user is the username for APN, or empty string
      * @param password is the password for APN, or empty string
      *
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index c49286b..e25a30c 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -1934,4 +1934,13 @@
      */
     oneway getAllowedCarriersResponse(RadioResponseInfo info, bool allAllowed,
             CarrierRestrictions carriers);
+
+    /*
+     * Acknowldege the receipt of radio request sent to the vendor. This must be sent only for
+     * radio request which take long time to respond.
+     * For more details, refer https://source.android.com/devices/tech/connect/ril.html
+     *
+     * @param serial Serial no. of the request whose acknowledgement is sent.
+     */
+    oneway requestAcknowledgement(int32_t serial);
 };
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 194733a..9c4b453 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -1126,16 +1126,17 @@
 };
 
 struct GsmSignalStrength {
-    uint32_t signalStrength;              // Valid values are (0-31, 99) as defined in
-                                          // TS 27.007 8.5
+    uint32_t signalStrength;              // Valid values are (0-61, 99) as defined in
+                                          // TS 27.007 8.69
     uint32_t bitErrorRate;                // bit error rate (0-7, 99) as defined in TS 27.007 8.5
     int32_t timingAdvance;                // Timing Advance in bit periods. 1 bit period = 48/13 us.
                                           // INT_MAX denotes invalid value
 };
 
 struct WcdmaSignalStrength{
-    int32_t signalStrength;               // Valid values are (0-31, 99) as defined in TS 27.007 8.5
-    int32_t bitErrorRate;                 // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+    int32_t signalStrength;               // Valid values are (0-96, 99) as defined in
+                                          // TS 27.007 8.69
+    int32_t bitErrorRate;                 // bit error rate (0-49, 99) as defined in TS 27.007 8.69
 };
 
 struct CdmaSignalStrength {
diff --git a/tests/libhwbinder/aidl/Android.mk b/tests/libhwbinder/aidl/Android.mk
index ea25e80..1c175d8 100644
--- a/tests/libhwbinder/aidl/Android.mk
+++ b/tests/libhwbinder/aidl/Android.mk
@@ -10,6 +10,4 @@
   libbinder \
   libutils \
 
-LOCAL_STATIC_LIBRARIES := libtestUtil
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/vehicle/2.0/default/Android.mk b/vehicle/2.0/default/Android.mk
index 46733e5..e61aaa3 100644
--- a/vehicle/2.0/default/Android.mk
+++ b/vehicle/2.0/default/Android.mk
@@ -22,6 +22,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := $(module_prefix)-manager-lib
 LOCAL_SRC_FILES := \
+    vehicle_hal_manager/AccessControlConfigParser.cpp \
     vehicle_hal_manager/SubscriptionManager.cpp \
     vehicle_hal_manager/VehicleHalManager.cpp \
 
@@ -67,6 +68,7 @@
 LOCAL_WHOLE_STATIC_LIBRARIES := $(module_prefix)-manager-lib
 
 LOCAL_SRC_FILES:= \
+    tests/AccessControlConfigParser_test.cpp \
     tests/VehicleObjectPool_test.cpp \
     tests/VehiclePropConfigIndex_test.cpp \
     tests/SubscriptionManager_test.cpp \
diff --git a/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp b/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
new file mode 100644
index 0000000..92d7e39
--- /dev/null
+++ b/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <memory>
+#include <fstream>
+#include <unordered_set>
+
+#include "vehicle_hal_manager/AccessControlConfigParser.h"
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class AccessControlConfigParserTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        std::vector<VehicleProperty> supportedProperties {
+            VehicleProperty::HVAC_FAN_SPEED,
+            VehicleProperty::HVAC_FAN_DIRECTION,
+        };
+        parser.reset(new AccessControlConfigParser(supportedProperties));
+    }
+public:
+    PropertyAclMap aclMap;
+    std::unique_ptr<AccessControlConfigParser> parser;
+};
+
+TEST_F(AccessControlConfigParserTest, basicParsing) {
+    std::stringstream file;
+    file << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, multipleUids) {
+    std::stringstream file;
+    file << "Set AID_AUDIO 1004" << std::endl
+            << "Set AID_SYSTEM 1000" << std::endl
+            << "S:0x0500 AID_SYSTEM RW" << std::endl
+            << "S:0x0500 AID_AUDIO RW" << std::endl
+            << "S:0x0500 0xbeef R" << std::endl;  // Read-only.
+
+    std::unordered_set<unsigned> expectedUids {1000, 1004, 0xbeef};
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    auto range = aclMap.equal_range(VehicleProperty::HVAC_FAN_SPEED);
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+
+        ASSERT_EQ(1, expectedUids.count(acl.uid))
+                << " uid: " << std::hex << acl.uid;
+
+        if (acl.uid == 0xbeef) {
+            ASSERT_EQ(VehiclePropertyAccess::READ, acl.access);
+        } else {
+            ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, acl.access);
+        }
+    }
+}
+
+TEST_F(AccessControlConfigParserTest, fileContainsJunk) {
+    std::stringstream file;
+    file << "This string will be ignored with warning in the log" << std::endl
+         << "# However comments are quit legitimate" << std::endl
+         << "S:0x0500 0xbeef R # YAY" << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(0xbeef, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, badIntegerFormat) {
+    std::stringstream file;
+    file << "S:0x0500 A12 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, ignoreNotSupportedProperties) {
+    std::stringstream file;
+    file << "S:0x0666 1000 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, multipleCalls) {
+    std::stringstream configFile;
+    configFile << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&configFile, &aclMap));
+    ASSERT_EQ(1, aclMap.size());
+
+    std::stringstream configFile2;
+    configFile2 << "S:0x0501 1004 RW" << std::endl;
+    ASSERT_TRUE(parser->parseFromStream(&configFile2, &aclMap));
+    ASSERT_EQ(2, aclMap.size());
+
+    auto it = aclMap.find(VehicleProperty::HVAC_FAN_SPEED);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_SPEED, it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+
+    it = aclMap.find(VehicleProperty::HVAC_FAN_DIRECTION);
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(VehicleProperty::HVAC_FAN_DIRECTION, it->second.propId);
+    ASSERT_EQ(1004u, it->second.uid);
+}
+
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
diff --git a/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
new file mode 100644
index 0000000..1d436c5
--- /dev/null
+++ b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "android.hardware.vehicle@2.0-impl"
+#include <android/log.h>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+#include "AccessControlConfigParser.h"
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+AccessControlConfigParser::AccessControlConfigParser(
+        const std::vector<VehicleProperty>& properties) {
+    // Property Id in the config file doesn't include information about
+    // type and area. So we want to create a map from these kind of
+    // *stripped* properties to the whole VehicleProperty.
+    // We also want to filter out ACL to the properties that supported
+    // by concrete Vehicle HAL implementation.
+    for (VehicleProperty vehicleProperty : properties) {
+        auto numProp = static_cast<int>(vehicleProperty);
+        numProp &= ~static_cast<int>(VehiclePropertyType::MASK)
+                & ~static_cast<int>(VehicleArea::MASK);
+        mStrippedToVehiclePropertyMap.emplace(numProp, vehicleProperty);
+    }
+}
+
+bool AccessControlConfigParser::parseFromStream(
+        std::istream* stream, PropertyAclMap* propertyAclMap) {
+    std::list<std::string> tokens;
+    std::string line;
+    int lineNo = 0;
+    bool warnings = false;
+    for (;std::getline(*stream, line); lineNo++) {
+        split(line, &tokens);
+        if (!processTokens(&tokens, propertyAclMap)) {
+            warnings = true;
+            ALOGW("Failed to parse line %d : %s", lineNo, line.c_str());
+        }
+    }
+    return !warnings;
+}
+
+
+bool AccessControlConfigParser::processTokens(std::list<std::string>* tokens,
+                                              PropertyAclMap* propertyAclMap) {
+    std::string token = readNextToken(tokens);
+    if (token.empty() || token[0] == '#') {   // Ignore comment.
+        return true;
+    }
+
+    if (token == "Set") {
+        std::string alias = readNextToken(tokens);
+        std::string strUid = readNextToken(tokens);
+        if (alias.empty() || strUid.empty()) {
+            ALOGW("Expected alias and UID must be specified");
+            return false;
+        }
+        int uid;
+        if (!parseInt(strUid.c_str(), &uid)) {
+            ALOGW("Invalid UID: %d", uid);
+        }
+        mUidMap.emplace(std::move(alias), uid);
+    } else if (token.size() > 2 && token[1] == ':') {
+        VehiclePropertyGroup propGroup;
+        if (!parsePropertyGroup(token[0], &propGroup)) {
+            return false;
+        }
+        std::string strUid = readNextToken(tokens);
+        std::string strAccess = readNextToken(tokens);
+        if (strUid.empty() || strAccess.empty()) {
+            ALOGW("Expected UID and access for property: %s",
+                  token.c_str());
+        }
+
+
+        PropertyAcl acl;
+        if (parsePropertyId(token.substr(2), propGroup, &acl.propId)
+            && parseUid(strUid, &acl.uid)
+            && parseAccess(strAccess, &acl.access)) {
+            propertyAclMap->emplace(acl.propId, std::move(acl));
+        } else {
+            return false;
+        }
+    } else {
+        ALOGW("Unexpected token: %s", token.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyGroup(
+        char group, VehiclePropertyGroup* outPropertyGroup) const {
+    switch (group) {
+        case 'S':  // Fall through.
+        case 's':
+            *outPropertyGroup = VehiclePropertyGroup::SYSTEM;
+            break;
+        case 'V':  // Fall through.
+        case 'v':
+            *outPropertyGroup = VehiclePropertyGroup::VENDOR;
+            break;
+        default:
+            ALOGW("Unexpected group: %c", group);
+            return false;
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyId(
+        const std::string& strPropId,
+        VehiclePropertyGroup propertyGroup,
+        VehicleProperty* outVehicleProperty) const {
+    int propId;
+    if (!parseInt(strPropId.c_str(), &propId)) {
+        ALOGW("Failed to convert property id to integer: %s",
+              strPropId.c_str());
+        return false;
+    }
+    propId |= static_cast<int>(propertyGroup);
+    auto it = mStrippedToVehiclePropertyMap.find(propId);
+    if (it == mStrippedToVehiclePropertyMap.end()) {
+        ALOGW("Property Id not found or not supported: 0x%x", propId);
+        return false;
+    }
+    *outVehicleProperty = it->second;
+    return true;
+}
+
+bool AccessControlConfigParser::parseInt(const char* strValue,
+                                         int* outIntValue) {
+    char* end;
+    long num = std::strtol(strValue, &end, 0 /* auto detect base */);
+    bool success = *end == 0 && errno != ERANGE;
+    if (success) {
+        *outIntValue = static_cast<int>(num);
+    }
+
+    return success;
+}
+
+bool AccessControlConfigParser::parseUid(const std::string& strUid,
+                                         unsigned* outUid) const {
+    auto element = mUidMap.find(strUid);
+    if (element != mUidMap.end()) {
+        *outUid = element->second;
+    } else {
+        int val;
+        if (!parseInt(strUid.c_str(), &val)) {
+            ALOGW("Failed to convert UID '%s' to integer", strUid.c_str());
+            return false;
+        }
+        *outUid = static_cast<unsigned>(val);
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parseAccess(
+        const std::string& strAccess, VehiclePropertyAccess* outAccess) const {
+    if (strAccess.size() == 0 || strAccess.size() > 2) {
+        ALOGW("Unknown access mode '%s'", strAccess.c_str());
+        return false;
+    }
+    int32_t access = static_cast<int32_t>(VehiclePropertyAccess::NONE);
+    for (char c : strAccess) {
+        if (c == 'R' || c == 'r') {
+            access |= VehiclePropertyAccess::READ;
+        } else if (c == 'W' || c == 'w') {
+            access |= VehiclePropertyAccess::WRITE;
+        } else {
+            ALOGW("Unknown access mode: %c", c);
+            return false;
+        }
+    }
+    *outAccess = static_cast<VehiclePropertyAccess>(access);
+    return true;
+}
+
+void AccessControlConfigParser::split(const std::string& line,
+                                      std::list<std::string>* outTokens) {
+    outTokens->clear();
+    std::istringstream iss(line);
+
+    while (!iss.eof()) {
+        std::string token;
+        iss >> token;
+        outTokens->push_back(std::move(token));
+    }
+}
+
+std::string AccessControlConfigParser::readNextToken(
+        std::list<std::string>* tokens) const {
+    if (tokens->empty()) {
+        return "";
+    }
+
+    std::string token = tokens->front();
+    tokens->pop_front();
+    return token;
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
diff --git a/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
new file mode 100644
index 0000000..17cbbd6
--- /dev/null
+++ b/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
+#define android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <list>
+#include <android/hardware/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace vehicle {
+namespace V2_0 {
+
+struct PropertyAcl {
+    VehicleProperty propId;
+    unsigned uid;
+    VehiclePropertyAccess access;
+};
+
+using PropertyAclMap = std::unordered_multimap<VehicleProperty, PropertyAcl>;
+
+/**
+ * Parser for per-property access control in vehicle HAL.
+ *
+ * It supports the following format:
+ *   Set ALIAS_NAME UID
+ *   {S,V}:0x0305   {ALIAS_NAME,UID}   {R,W,RW}
+ *
+ * ALIAS_NAME is just an alias for UID
+ * S - for system properties (VehiclePropertyGroup::SYSTEM)
+ * V - for vendor properties (VehiclePropertyGroup::VENDOR)
+ *
+ * Example:
+ *
+ *   Set AID_AUDIO  1004
+ *   Set AID_MY_APP     10022
+ *
+ *   S:0x0305   AID_AUDIO   RW
+ *   S:0x0305   10021       R
+ *   V:0x0101   AID_MY_APP  R
+ */
+class AccessControlConfigParser {
+public:
+    /**
+     * Creates an instance of AccessControlConfigParser
+     *
+     * @param properties - properties supported by HAL implementation
+     */
+    AccessControlConfigParser(const std::vector<VehicleProperty>& properties);
+
+    /**
+     * Parses config content from given stream and writes results to
+     * propertyAclMap.
+     */
+    bool parseFromStream(std::istream* stream, PropertyAclMap* propertyAclMap);
+
+private:
+    bool processTokens(std::list<std::string>* tokens,
+                       PropertyAclMap* propertyAclMap);
+
+    bool parsePropertyGroup(char group,
+                            VehiclePropertyGroup* outPropertyGroup) const;
+
+    bool parsePropertyId(const std::string& strPropId,
+                                VehiclePropertyGroup propertyGroup,
+                                VehicleProperty* outVehicleProperty) const;
+
+    bool parseUid(const std::string& strUid, unsigned* outUid) const;
+
+    bool parseAccess(const std::string& strAccess,
+                     VehiclePropertyAccess* outAccess) const;
+
+
+    std::string readNextToken(std::list<std::string>* tokens) const;
+
+    static bool parseInt(const char* strValue, int* outIntValue);
+    static void split(const std::string& line,
+                      std::list<std::string>* outTokens);
+
+private:
+    std::unordered_map<std::string, unsigned> mUidMap {};  // Contains UID
+    // aliases.
+
+    // Map property ids w/o TYPE and AREA to VehicleProperty.
+    std::unordered_map<int, VehicleProperty> mStrippedToVehiclePropertyMap;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_vehicle_V2_0_AccessControlConfigParser_H_
diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
index 1260f20..267c515 100644
--- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
+++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
@@ -22,6 +22,8 @@
 #include <hidl/Status.h>
 #include <future>
 #include <bitset>
+#include <fstream>
+#include <private/android_filesystem_config.h>
 
 #include "VehicleHalManager.h"
 
@@ -52,10 +54,8 @@
             const_cast<VehiclePropConfig *>(halConfig.data()),
             halConfig.size());
 
-    ALOGI("getAllPropConfigs calling callback");
     _hidl_cb(hidlConfigs);
 
-    ALOGI("getAllPropConfigs done");
     return Void();
 }
 
@@ -88,7 +88,7 @@
         return Void();
     }
 
-    if (!checkReadPermission(*config, getCallee())) {
+    if (!checkReadPermission(*config, getCaller())) {
         _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
         return Void();
     }
@@ -109,7 +109,7 @@
         return StatusCode::INVALID_ARG;
     }
 
-    if (!checkWritePermission(*config, getCallee())) {
+    if (!checkWritePermission(*config, getCaller())) {
         return StatusCode::INVALID_ARG;
     }
 
@@ -194,7 +194,21 @@
                          _1, _2, _3));
 
     // Initialize index with vehicle configurations received from VehicleHal.
-    mConfigIndex.reset(new VehiclePropConfigIndex(mHal->listProperties()));
+    auto supportedPropConfigs = mHal->listProperties();
+    mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
+
+    std::vector<VehicleProperty> supportedProperties(
+        supportedPropConfigs.size());
+    for (const auto& config : supportedPropConfigs) {
+        supportedProperties.push_back(config.prop);
+    }
+
+    AccessControlConfigParser aclParser(supportedProperties);
+    const char* configs[] = { "/system/etc/vehicle_access.conf",
+                              "/vendor/etc/vehicle_access.conf" };
+    for (const char* filename : configs) {
+        readAndParseAclConfig(filename, &aclParser, &mPropertyAclMap);
+    }
 }
 
 VehicleHalManager::~VehicleHalManager() {
@@ -292,24 +306,43 @@
     return true;
 }
 
+bool checkAcl(const PropertyAclMap& aclMap,
+              uid_t callerUid,
+              VehicleProperty propertyId,
+              VehiclePropertyAccess requiredAccess) {
+    if (callerUid == AID_SYSTEM && isSystemProperty(propertyId)) {
+        return true;
+    }
+
+    auto range = aclMap.equal_range(propertyId);
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+        if (acl.uid == callerUid && (acl.access & requiredAccess)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config,
-                                             const Callee& callee) {
+                                             const Caller& caller) const {
     if (!(config.access & VehiclePropertyAccess::WRITE)) {
         ALOGW("Property 0%x has no write access", config.prop);
         return false;
     }
-    //TODO(pavelm): check pid/uid has write access
-    return true;
+    return checkAcl(mPropertyAclMap, caller.uid, config.prop,
+                    VehiclePropertyAccess::WRITE);
 }
 
 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config,
-                                            const Callee& callee) {
+                                            const Caller& caller) const {
     if (!(config.access & VehiclePropertyAccess::READ)) {
         ALOGW("Property 0%x has no read access", config.prop);
         return false;
     }
-    //TODO(pavelm): check pid/uid has read access
-    return true;
+
+    return checkAcl(mPropertyAclMap, caller.uid, config.prop,
+                    VehiclePropertyAccess::READ);
 }
 
 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
@@ -326,13 +359,24 @@
            ? &mConfigIndex->getConfig(prop) : nullptr;
 }
 
-Callee VehicleHalManager::getCallee() {
-    Callee callee;
+Caller VehicleHalManager::getCaller() {
+    Caller caller;
     IPCThreadState* self = IPCThreadState::self();
-    callee.pid = self->getCallingPid();
-    callee.uid = self->getCallingUid();
+    caller.pid = self->getCallingPid();
+    caller.uid = self->getCallingUid();
 
-    return callee;
+    return caller;
+}
+
+void VehicleHalManager::readAndParseAclConfig(const char* filename,
+                                              AccessControlConfigParser* parser,
+                                              PropertyAclMap* outAclMap) {
+    std::ifstream file(filename);
+    if (file.is_open()) {
+        ALOGI("Parsing file: %s", filename);
+        parser->parseFromStream(&file, outAclMap);
+        file.close();
+    }
 }
 
 }  // namespace V2_0
diff --git a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
index 8353679..cb846c9 100644
--- a/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
+++ b/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
@@ -29,10 +29,11 @@
 
 #include <android/hardware/vehicle/2.0/IVehicle.h>
 
-#include "VehicleHal.h"
-#include "VehiclePropConfigIndex.h"
+#include "AccessControlConfigParser.h"
 #include "ConcurrentQueue.h"
 #include "SubscriptionManager.h"
+#include "VehicleHal.h"
+#include "VehiclePropConfigIndex.h"
 #include "VehicleObjectPool.h"
 
 namespace android {
@@ -40,7 +41,7 @@
 namespace vehicle {
 namespace V2_0 {
 
-struct Callee {
+struct Caller {
     pid_t pid;
     uid_t uid;
 };
@@ -95,17 +96,21 @@
 
     const VehiclePropConfig* getPropConfigOrNull(VehicleProperty prop) const;
 
+    bool checkWritePermission(const VehiclePropConfig &config,
+                              const Caller& callee) const;
+    bool checkReadPermission(const VehiclePropConfig &config,
+                             const Caller& caller) const;
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
     static float checkSampleRate(const VehiclePropConfig& config,
                                  float sampleRate);
-    static bool checkWritePermission(const VehiclePropConfig &config,
-                                     const Callee& callee);
-    static bool checkReadPermission(const VehiclePropConfig &config,
-                                    const Callee& callee);
+    static void readAndParseAclConfig(const char* filename,
+                                      AccessControlConfigParser* parser,
+                                      PropertyAclMap* outAclMap);
 
-    static Callee getCallee();
+    static Caller getCaller();
 
 private:
     VehicleHal* mHal;
@@ -117,6 +122,7 @@
     ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
     BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer;
     VehiclePropValuePool mValueObjectPool;
+    PropertyAclMap mPropertyAclMap;
 };
 
 }  // namespace V2_0
diff --git a/vehicle/2.0/types.hal b/vehicle/2.0/types.hal
index 0e0e3ea..72fa554 100644
--- a/vehicle/2.0/types.hal
+++ b/vehicle/2.0/types.hal
@@ -2136,6 +2136,8 @@
  * the expected output.
  */
 enum VehiclePropertyAccess : int32_t {
+  NONE = 0x00,
+
   READ = 0x01,
   WRITE = 0x02,
   READ_WRITE = 0x03,
diff --git a/vehicle/2.0/vts/functional/Android.mk b/vehicle/2.0/vts/functional/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/Android.mk b/vehicle/2.0/vts/functional/vts/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/testcases/Android.mk b/vehicle/2.0/vts/functional/vts/testcases/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/Android.mk b/vehicle/2.0/vts/functional/vts/testcases/hal/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/Android.mk b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/__init__.py b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/__init__.py
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/Android.mk b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/__init__.py b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/__init__.py
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/Android.mk b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/Android.mk
new file mode 100644
index 0000000..716a41c
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/Android.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VehicleHidlTest
+VTS_CONFIG_SRC_DIR := testcases/hal/vehicle/hidl/host
+include test/vts/tools/build/Android.host_config.mk
\ No newline at end of file
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/AndroidTest.xml b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/AndroidTest.xml
new file mode 100644
index 0000000..16b7c29
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for VTS HAL Vehicle test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+        <option name="push-group" value="HidlHalTest.push" />
+        <option name="cleanup" value="true" />
+        <option name="push" value="spec/hardware/interfaces/vehicle/2.0/vts/Vehicle.vts->/data/local/tmp/spec/Vehicle.vts" />
+        <option name="push" value="spec/hardware/interfaces/vehicle/2.0/vts/VehicleCallback.vts->/data/local/tmp/spec/VehicleCallBack.vts" />
+        <option name="push" value="spec/hardware/interfaces/vehicle/2.0/vts/types.vts->/data/local/tmp/spec/types.vts" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+        <option name="test-module-name" value="VehicleHidlTest" />
+        <option name="test-case-path" value="vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest" />
+    </test>
+</configuration>
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py
new file mode 100644
index 0000000..bc37e59
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/VehicleHidlTest.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import logging
+import time
+
+from vts.runners.host import asserts
+from vts.runners.host import base_test_with_webdb
+from vts.runners.host import test_runner
+from vts.utils.python.controllers import android_device
+from vts.utils.python.profiling import profiling_utils
+
+
+class VehicleHidlTest(base_test_with_webdb.BaseTestWithWebDbClass):
+    """A simple testcase for the VEHICLE HIDL HAL."""
+
+    def setUpClass(self):
+        """Creates a mirror and init vehicle hal."""
+        self.dut = self.registerController(android_device)[0]
+
+        self.dut.shell.InvokeTerminal("one")
+
+        if self.enable_profiling:
+            profiling_utils.EnableVTSProfiling(self.dut.shell.one)
+
+        self.dut.hal.InitHidlHal(
+            target_type="vehicle",
+            target_basepaths=["/system/lib64"],
+            target_version=2.0,
+            target_package="android.hardware.vehicle",
+            target_component_name="IVehicle",
+            bits=64)
+
+    def tearDownClass(self):
+        """ If profiling is enabled for the test, collect the profiling data
+            and disable profiling after the test is done.
+        """
+        if self.enable_profiling:
+            profiling_trace_path = getattr(
+                self, self.VTS_PROFILING_TRACING_PATH, "")
+            self.ProcessAndUploadTraceData(self.dut, profiling_trace_path)
+            profiling_utils.DisableVTSProfiling(self.dut.shell.one)
+
+    def testEcho1(self):
+        """A simple testcase which sends a command."""
+        self.dut.shell.InvokeTerminal("my_shell1")  # creates a remote shell instance.
+        results = self.dut.shell.my_shell1.Execute("echo hello_world")  # runs a shell command.
+        logging.info(str(results[const.STDOUT]))  # prints the stdout
+        asserts.assertEqual(results[const.STDOUT][0].strip(), "hello_world")  # checks the stdout
+        asserts.assertEqual(results[const.EXIT_CODE][0], 0)  # checks the exit code
+
+    def testEcho2(self):
+        """A simple testcase which sends two commands."""
+        self.dut.shell.InvokeTerminal("my_shell2")
+        my_shell = getattr(self.dut.shell, "my_shell2")
+        results = my_shell.Execute(["echo hello", "echo world"])
+        logging.info(str(results[const.STDOUT]))
+        asserts.assertEqual(len(results[const.STDOUT]), 2)  # check the number of processed commands
+        asserts.assertEqual(results[const.STDOUT][0].strip(), "hello")
+        asserts.assertEqual(results[const.STDOUT][1].strip(), "world")
+        asserts.assertEqual(results[const.EXIT_CODE][0], 0)
+        asserts.assertEqual(results[const.EXIT_CODE][1], 0)
+
+if __name__ == "__main__":
+    test_runner.main()
diff --git a/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/__init__.py b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vehicle/2.0/vts/functional/vts/testcases/hal/vehicle/hidl/host/__init__.py
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp
index e893ec6..a24cf5c 100644
--- a/vibrator/1.0/vts/functional/Android.bp
+++ b/vibrator/1.0/vts/functional/Android.bp
@@ -20,6 +20,7 @@
     srcs: ["vibrator_hidl_hal_test.cpp"],
     shared_libs: [
         "libbase",
+        "libhidlbase",
         "liblog",
         "libutils",
         "android.hardware.vibrator@1.0",
diff --git a/wifi/1.0/Android.mk b/wifi/1.0/Android.mk
index 7f158d4..254a15a 100644
--- a/wifi/1.0/Android.mk
+++ b/wifi/1.0/Android.mk
@@ -1176,25 +1176,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (RttChannelMap)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttChannelMap.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttChannelMap
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (RttConfig)
 #
 GEN := $(intermediates)/android/hardware/wifi/1.0/RttConfig.java
@@ -1214,63 +1195,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (RttDebugFormat)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugFormat.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugFormat
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (RttDebugInfo)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugInfo.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugInfo
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (RttDebugType)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (RttLciInformation)
 #
 GEN := $(intermediates)/android/hardware/wifi/1.0/RttLciInformation.java
@@ -3737,25 +3661,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (RttChannelMap)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttChannelMap.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttChannelMap
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (RttConfig)
 #
 GEN := $(intermediates)/android/hardware/wifi/1.0/RttConfig.java
@@ -3775,63 +3680,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (RttDebugFormat)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugFormat.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugFormat
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (RttDebugInfo)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugInfo.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugInfo
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (RttDebugType)
-#
-GEN := $(intermediates)/android/hardware/wifi/1.0/RttDebugType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.wifi@1.0::types.RttDebugType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (RttLciInformation)
 #
 GEN := $(intermediates)/android/hardware/wifi/1.0/RttLciInformation.java
diff --git a/wifi/1.0/IWifiRttController.hal b/wifi/1.0/IWifiRttController.hal
index 93b3d92..2f81176 100644
--- a/wifi/1.0/IWifiRttController.hal
+++ b/wifi/1.0/IWifiRttController.hal
@@ -83,45 +83,6 @@
       generates (WifiStatus status);
 
   /**
-   * API to start publishing the channel map on responder device in an NBD
-   * cluster.
-   * Responder device must take this request and schedule broadcasting the
-   * channel map in a NBD ranging attribute in a Service Discovery Frame.
-   * DE must automatically remove the ranging attribute from the OTA queue
-   * after number of Discovery Window specified by numDw where each
-   * Discovery Window is 512 TUs apart.
-   *
-   * @param cmdId command Id to use for this invocation.
-   * @param params Instance of |RttChannelMap|.
-   * @return status WifiStatus of the operation.
-   *         Possible status codes:
-   *         |WifiStatusCode.SUCCESS|,
-   *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
-   *         |WifiStatusCode.ERROR_INVALID_ARGS|,
-   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
-   *         |WifiStatusCode.ERROR_UNKNOWN|
-   */
-  setChannelMap(CommandId cmdId, RttChannelMap params, uint32_t numDw)
-      generates (WifiStatus status);
-
-  /**
-   * API to clear the channel map on the responder device in an NBD cluster.
-   * Responder device must cancel future ranging channel request, starting from
-   * next Discovery Window interval and must also stop broadcasting NBD
-   * ranging attribute in Service Discovery Frame.
-   *
-   * @param cmdId command Id corresponding to the original request.
-   * @return status WifiStatus of the operation.
-   *         Possible status codes:
-   *         |WifiStatusCode.SUCCESS|,
-   *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
-   *         |WifiStatusCode.ERROR_INVALID_ARGS|,
-   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
-   *         |WifiStatusCode.ERROR_UNKNOWN|
-   */
-  clearChannelMap(CommandId cmdId) generates (WifiStatus status);
-
-  /**
    * RTT capabilities of the device.
    *
    * @return status WifiStatus of the operation.
@@ -134,32 +95,6 @@
   getCapabilities() generates (WifiStatus status, RttCapabilities capabilities);
 
   /**
-   * Set configuration for debug.
-   *
-   * @param type debug level to be set.
-   * @return status WifiStatus of the operation.
-   *         Possible status codes:
-   *         |WifiStatusCode.SUCCESS|,
-   *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
-   *         |WifiStatusCode.ERROR_INVALID_ARGS|,
-   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
-   *         |WifiStatusCode.ERROR_UNKNOWN|
-   */
-  setDebugCfg(RttDebugType Type) generates (WifiStatus status);
-
-  /**
-   * Get the debug information.
-   *
-   * @return status WifiStatus of the operation.
-   *         Possible status codes:
-   *         |WifiStatusCode.ERROR_WIFI_RTT_CONTROLLER_INVALID|,
-   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
-   *         |WifiStatusCode.ERROR_UNKNOWN|
-   * @return info Instance of |RttDebugInfo|.
-   */
-  getDebugInfo() generates (WifiStatus status, RttDebugInfo info);
-
-  /**
    * API to configure the LCI(Location civic information).
    * Used in RTT Responder mode only.
    *
diff --git a/wifi/1.0/IWifiStaIface.hal b/wifi/1.0/IWifiStaIface.hal
index 41b2bad..7b514a7 100644
--- a/wifi/1.0/IWifiStaIface.hal
+++ b/wifi/1.0/IWifiStaIface.hal
@@ -45,9 +45,13 @@
      */
     LINK_LAYER_STATS = 1 << 2,
     /**
+     * If set indicates that the RSSI monitor APIs are supported.
+     */
+    RSSI_MONITOR = 1 << 3,
+    /**
      * Tracks connection packets' fate.
      */
-    DEBUG_PACKET_FATE_SUPPORTED = 1 << 3
+    DEBUG_PACKET_FATE_SUPPORTED = 1 << 4
   };
 
   /**
@@ -259,6 +263,44 @@
   getLinkLayerStats() generates (WifiStatus status, StaLinkLayerStats stats);
 
   /**
+   * Start RSSI monitoring on the currently connected access point.
+   * Once the monitoring is enabled,
+   * |IWifiStaIfaceEventCallback.onRssiThresholdBreached| callback must be
+   * invoked to indicate if the RSSI goes above |maxRssi| or below |minRssi|.
+   * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+   *
+   * @param cmdId command Id to use for this invocation.
+   * @param maxRssi Maximum RSSI threshold.
+   * @param minRssi Minimum RSSI threshold.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+   *         |WifiStatusCode.ERROR_ARGS_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+   *         |WifiStatusCode.ERROR_UNKNOWN|
+   */
+  startRssiMonitoring(CommandId cmdId, Rssi maxRssi, Rssi minRssi)
+      generates (WifiStatus status);
+
+  /**
+   * Stop RSSI monitoring.
+   * Must fail if |StaIfaceCapabilityMask.RSSI_MONITOR| is not set.
+   *
+   * @param cmdId command Id corresponding to the request.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.ERROR_NOT_STARTED|,
+   *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+   *         |WifiStatusCode.ERROR_UNKNOWN|
+   */
+  stopRssiMonitoring(CommandId cmdId) generates (WifiStatus status);
+
+  /**
    * API to start packet fate monitoring.
    * - Once stared, monitoring must remain active until HAL is unloaded.
    * - When HAL is unloaded, all packet fate buffers must be cleared.
diff --git a/wifi/1.0/IWifiStaIfaceEventCallback.hal b/wifi/1.0/IWifiStaIfaceEventCallback.hal
index d47d40c..e8df4c2 100644
--- a/wifi/1.0/IWifiStaIfaceEventCallback.hal
+++ b/wifi/1.0/IWifiStaIfaceEventCallback.hal
@@ -20,6 +20,8 @@
   /**
    * Callback indicating that an ongoing background scan request has failed.
    * The background scan needs to be restarted to continue scanning.
+   *
+   * @param cmdId command ID corresponding to the request.
    */
   oneway onBackgroundScanFailure(CommandId cmdId);
 
@@ -28,7 +30,7 @@
    * |REPORT_EVENTS_FULL_RESULTS| flag set in
    * |StaBackgroundScanBucketParameters.eventReportScheme|.
    *
-   * @param cmdId command Id corresponding to the request.
+   * @param cmdId command ID corresponding to the request.
    * @parm result Full scan result for an AP.
    */
   oneway onBackgroundFullScanResult(CommandId cmdId, StaScanResult result);
@@ -39,8 +41,18 @@
    * |REPORT_EVENTS_EACH_SCAN| or one of the configured thresholds was
    * breached.
    *
-   * @param cmdId command Id corresponding to the request.
+   * @param cmdId command ID corresponding to the request.
    * @parm scanDatas List of scan result for all AP's seen since last callback.
    */
   oneway onBackgroundScanResults(CommandId cmdId, vec<StaScanData> scanDatas);
+
+  /**
+   * Called when the RSSI of the currently connected access point goes beyond the
+   * thresholds set via |IWifiStaIface.startRssiMonitoring|.
+   *
+   * @param cmdId command ID corresponding to the request.
+   * @param currBssid BSSID of the currently connected access point.
+   * @param currRssi RSSI of the currently connected access point.
+   */
+  oneway onRssiThresholdBreached(CommandId cmdId, Bssid currBssid, Rssi currRssi);
 };
diff --git a/wifi/1.0/default/Android.mk b/wifi/1.0/default/Android.mk
index 931a314..382d350 100644
--- a/wifi/1.0/default/Android.mk
+++ b/wifi/1.0/default/Android.mk
@@ -24,6 +24,7 @@
     wifi_ap_iface.cpp \
     wifi_chip.cpp \
     wifi_legacy_hal.cpp \
+    wifi_mode_controller.cpp \
     wifi_nan_iface.cpp \
     wifi_p2p_iface.cpp \
     wifi_rtt_controller.cpp \
@@ -39,6 +40,7 @@
     liblog \
     libnl \
     libutils \
+    libwifi-hal \
     libwifi-system
 LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL)
 LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index b4dcc0a..61a2c2c 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -26,7 +26,217 @@
 namespace implementation {
 namespace hidl_struct_util {
 
-uint8_t ConvertHidlReportEventFlagToLegacy(
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
+    uint32_t feature) {
+  using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+  switch (feature) {
+    case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+      return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP_SUPPORTED;
+    case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+      return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP_SUPPORTED;
+    case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+      return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT_SUPPORTED;
+    case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+      return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT_SUPPORTED;
+    case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+      return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT_SUPPORTED;
+  };
+  CHECK(false) << "Unknown legacy feature: " << feature;
+  return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
+  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+  switch (feature) {
+    case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+      return HidlStaIfaceCaps::DEBUG_PACKET_FATE_SUPPORTED;
+  };
+  CHECK(false) << "Unknown legacy feature: " << feature;
+  return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
+  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+  switch (feature) {
+    case WIFI_FEATURE_GSCAN:
+      return HidlStaIfaceCaps::BACKGROUND_SCAN;
+    case WIFI_FEATURE_LINK_LAYER_STATS:
+      return HidlStaIfaceCaps::LINK_LAYER_STATS;
+    case WIFI_FEATURE_RSSI_MONITOR:
+      return HidlStaIfaceCaps::RSSI_MONITOR;
+  };
+  CHECK(false) << "Unknown legacy feature: " << feature;
+  return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_logger_feature_set, uint32_t* hidl_caps) {
+  if (!hidl_caps) {
+    return false;
+  }
+  *hidl_caps = 0;
+  using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+  for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+                             legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+                             legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+                             legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+                             legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+    if (feature & legacy_logger_feature_set) {
+      *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
+    }
+  }
+  // There is no flags for these 2 in the legacy feature set. Adding it to the
+  // set because all the current devices support it.
+  *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA_SUPPORTED;
+  *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+  return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
+    uint32_t flag) {
+  switch (flag) {
+    case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+      return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+    case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+      return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+  };
+  CHECK(false) << "Unknown legacy flag: " << flag;
+  return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+    const legacy_hal::wifi_ring_buffer_status& legacy_status,
+    WifiDebugRingBufferStatus* hidl_status) {
+  if (!hidl_status) {
+    return false;
+  }
+  hidl_status->ringName = reinterpret_cast<const char*>(legacy_status.name);
+  for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
+                          WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+    if (flag & legacy_status.flags) {
+      hidl_status->flags |=
+          static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
+              convertLegacyDebugRingBufferFlagsToHidl(flag));
+    }
+  }
+  hidl_status->ringId = legacy_status.ring_id;
+  hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+  // Calculate free size of the ring the buffer. We don't need to send the
+  // exact read/write pointers that were there in the legacy HAL interface.
+  if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+    hidl_status->freeSizeInBytes =
+        legacy_status.ring_buffer_byte_size -
+        (legacy_status.written_bytes - legacy_status.read_bytes);
+  } else {
+    hidl_status->freeSizeInBytes =
+        legacy_status.read_bytes - legacy_status.written_bytes;
+  }
+  hidl_status->verboseLevel = legacy_status.verbose_level;
+  return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+  if (!hidl_status_vec) {
+    return false;
+  }
+  hidl_status_vec->clear();
+  for (const auto& legacy_status : legacy_status_vec) {
+    WifiDebugRingBufferStatus hidl_status;
+    if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
+                                                  &hidl_status)) {
+      return false;
+    }
+    hidl_status_vec->push_back(hidl_status);
+  }
+  return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats) {
+  if (!hidl_stats) {
+    return false;
+  }
+  hidl_stats->totalCmdEventWakeCnt =
+      legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+  hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+  hidl_stats->totalDriverFwLocalWakeCnt =
+      legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+  hidl_stats->driverFwLocalWakeCntPerType =
+      legacy_stats.driver_fw_local_wake_cnt;
+  hidl_stats->totalRxPacketWakeCnt =
+      legacy_stats.wake_reason_cnt.total_rx_data_wake;
+  hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+      legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+  hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+      legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+  hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+      legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+  hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+          .ipv4_rx_multicast_addr_cnt;
+  hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+          .ipv6_rx_multicast_addr_cnt;
+  hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+          .other_rx_multicast_addr_cnt;
+  hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+  hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+  hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+  hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+  hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+  return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint32_t legacy_feature_set,
+    uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps) {
+  if (!hidl_caps) {
+    return false;
+  }
+  *hidl_caps = 0;
+  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+  for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+    if (feature & legacy_logger_feature_set) {
+      *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+    }
+  }
+  for (const auto feature : {WIFI_FEATURE_GSCAN,
+                             WIFI_FEATURE_LINK_LAYER_STATS,
+                             WIFI_FEATURE_RSSI_MONITOR}) {
+    if (feature & legacy_feature_set) {
+      *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+    }
+  }
+  // There is no flag for this one in the legacy feature set. Adding it to the
+  // set because all the current devices support it.
+  *hidl_caps |= HidlStaIfaceCaps::APF;
+  return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps) {
+  if (!hidl_caps) {
+    return false;
+  }
+  hidl_caps->version = legacy_caps.version;
+  hidl_caps->maxLength = legacy_caps.max_len;
+  return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
     StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
   using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
   switch (hidl_flag) {
@@ -37,9 +247,54 @@
     case HidlFlag::NO_BATCH:
       return REPORT_EVENTS_NO_BATCH;
   };
+  CHECK(false);
 }
 
-bool convertHidlScanParamsToLegacy(
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+  switch (legacy_flag) {
+    case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+      return StaScanDataFlagMask::INTERRUPTED;
+  };
+  CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+  // To silence the compiler warning about reaching the end of non-void
+  // function.
+  return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps) {
+  if (!hidl_caps) {
+    return false;
+  }
+  hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+  hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+  hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+  hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+  return true;
+}
+
+legacy_hal::wifi_band convertHidlGscanBandToLegacy(StaBackgroundScanBand band) {
+  switch (band) {
+    case StaBackgroundScanBand::BAND_UNSPECIFIED:
+      return legacy_hal::WIFI_BAND_UNSPECIFIED;
+    case StaBackgroundScanBand::BAND_24GHZ:
+      return legacy_hal::WIFI_BAND_BG;
+    case StaBackgroundScanBand::BAND_5GHZ:
+      return legacy_hal::WIFI_BAND_A;
+    case StaBackgroundScanBand::BAND_5GHZ_DFS:
+      return legacy_hal::WIFI_BAND_A_DFS;
+    case StaBackgroundScanBand::BAND_5GHZ_WITH_DFS:
+      return legacy_hal::WIFI_BAND_A_WITH_DFS;
+    case StaBackgroundScanBand::BAND_24GHZ_5GHZ:
+      return legacy_hal::WIFI_BAND_ABG;
+    case StaBackgroundScanBand::BAND_24GHZ_5GHZ_WITH_DFS:
+      return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+  };
+  CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(
     const StaBackgroundScanParameters& hidl_scan_params,
     legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
   if (!legacy_scan_params) {
@@ -76,7 +331,7 @@
       if (hidl_bucket_spec.eventReportScheme &
           static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
         legacy_bucket_spec.report_events |=
-            ConvertHidlReportEventFlagToLegacy(flag);
+            convertHidlGscanReportEventFlagToLegacy(flag);
       }
     }
     // TODO(b/33194311): Expose these max limits in the HIDL interface.
@@ -93,6 +348,18 @@
   return true;
 }
 
+bool convertLegacyIeToHidl(
+    const legacy_hal::wifi_information_element& legacy_ie,
+    WifiInformationElement* hidl_ie) {
+  if (!hidl_ie) {
+    return false;
+  }
+  hidl_ie->id = legacy_ie.id;
+  hidl_ie->data =
+      std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+  return true;
+}
+
 bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob,
                                uint32_t ie_blob_len,
                                std::vector<WifiInformationElement>* hidl_ies) {
@@ -112,9 +379,9 @@
       return false;
     }
     WifiInformationElement hidl_ie;
-    hidl_ie.id = legacy_ie.id;
-    hidl_ie.data =
-        std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+    if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+      return false;
+    }
     hidl_ies->push_back(std::move(hidl_ie));
     next_ie += curr_ie_len;
   }
@@ -122,7 +389,7 @@
   return (next_ie == ies_end);
 }
 
-bool convertLegacyScanResultToHidl(
+bool convertLegacyGscanResultToHidl(
     const legacy_hal::wifi_scan_result& legacy_scan_result,
     bool has_ie_data,
     StaScanResult* hidl_scan_result) {
@@ -153,13 +420,19 @@
   return true;
 }
 
-bool convertLegacyCachedScanResultsToHidl(
+bool convertLegacyCachedGscanResultsToHidl(
     const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
     StaScanData* hidl_scan_data) {
   if (!hidl_scan_data) {
     return false;
   }
-  hidl_scan_data->flags = legacy_cached_scan_result.flags;
+  for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+    if (legacy_cached_scan_result.flags & flag) {
+      hidl_scan_data->flags |=
+          static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+              convertLegacyGscanDataFlagToHidl(flag));
+    }
+  }
   hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
 
   CHECK(legacy_cached_scan_result.num_results >= 0 &&
@@ -169,7 +442,7 @@
        result_idx < legacy_cached_scan_result.num_results;
        result_idx++) {
     StaScanResult hidl_scan_result;
-    if (!convertLegacyScanResultToHidl(
+    if (!convertLegacyGscanResultToHidl(
             legacy_cached_scan_result.results[result_idx],
             false,
             &hidl_scan_result)) {
@@ -181,17 +454,18 @@
   return true;
 }
 
-bool convertLegacyVectorOfCachedScanResultsToHidl(
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
     const std::vector<legacy_hal::wifi_cached_scan_results>&
         legacy_cached_scan_results,
     std::vector<StaScanData>* hidl_scan_datas) {
   if (!hidl_scan_datas) {
     return false;
   }
+  hidl_scan_datas->clear();
   for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
     StaScanData hidl_scan_data;
-    if (!convertLegacyCachedScanResultsToHidl(legacy_cached_scan_result,
-                                              &hidl_scan_data)) {
+    if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
+                                               &hidl_scan_data)) {
       return false;
     }
     hidl_scan_datas->push_back(hidl_scan_data);
@@ -199,6 +473,149 @@
   return true;
 }
 
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
+    legacy_hal::wifi_tx_packet_fate fate) {
+  switch (fate) {
+    case legacy_hal::TX_PKT_FATE_ACKED:
+      return WifiDebugTxPacketFate::ACKED;
+    case legacy_hal::TX_PKT_FATE_SENT:
+      return WifiDebugTxPacketFate::SENT;
+    case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+      return WifiDebugTxPacketFate::FW_QUEUED;
+    case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+      return WifiDebugTxPacketFate::FW_DROP_INVALID;
+    case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+      return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+    case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+      return WifiDebugTxPacketFate::FW_DROP_OTHER;
+    case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+      return WifiDebugTxPacketFate::DRV_QUEUED;
+    case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+      return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+    case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+      return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+    case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+      return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+  };
+  CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
+    legacy_hal::wifi_rx_packet_fate fate) {
+  switch (fate) {
+    case legacy_hal::RX_PKT_FATE_SUCCESS:
+      return WifiDebugRxPacketFate::SUCCESS;
+    case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+      return WifiDebugRxPacketFate::FW_QUEUED;
+    case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+      return WifiDebugRxPacketFate::FW_DROP_FILTER;
+    case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+      return WifiDebugRxPacketFate::FW_DROP_INVALID;
+    case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+      return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+    case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+      return WifiDebugRxPacketFate::FW_DROP_OTHER;
+    case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+      return WifiDebugRxPacketFate::DRV_QUEUED;
+    case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+      return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+    case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+      return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+    case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+      return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+    case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+      return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+  };
+  CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+    legacy_hal::frame_type type) {
+  switch (type) {
+    case legacy_hal::FRAME_TYPE_UNKNOWN:
+      return WifiDebugPacketFateFrameType::UNKNOWN;
+    case legacy_hal::FRAME_TYPE_ETHERNET_II:
+      return WifiDebugPacketFateFrameType::ETHERNET_II;
+    case legacy_hal::FRAME_TYPE_80211_MGMT:
+      return WifiDebugPacketFateFrameType::MGMT_80211;
+  };
+  CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(
+    const legacy_hal::frame_info& legacy_frame,
+    WifiDebugPacketFateFrameInfo* hidl_frame) {
+  if (!hidl_frame) {
+    return false;
+  }
+  hidl_frame->frameType =
+      convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+  hidl_frame->frameLen = legacy_frame.frame_len;
+  hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+  hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+  const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
+      legacy_frame.frame_content.ethernet_ii_bytes);
+  hidl_frame->frameContent =
+      std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+  return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(
+    const legacy_hal::wifi_tx_report& legacy_fate,
+    WifiDebugTxPacketFateReport* hidl_fate) {
+  if (!hidl_fate) {
+    return false;
+  }
+  hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+  return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                 &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+  if (!hidl_fates) {
+    return false;
+  }
+  hidl_fates->clear();
+  for (const auto& legacy_fate : legacy_fates) {
+    WifiDebugTxPacketFateReport hidl_fate;
+    if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+      return false;
+    }
+    hidl_fates->push_back(hidl_fate);
+  }
+  return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(
+    const legacy_hal::wifi_rx_report& legacy_fate,
+    WifiDebugRxPacketFateReport* hidl_fate) {
+  if (!hidl_fate) {
+    return false;
+  }
+  hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+  return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                 &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+  if (!hidl_fates) {
+    return false;
+  }
+  hidl_fates->clear();
+  for (const auto& legacy_fate : legacy_fates) {
+    WifiDebugRxPacketFateReport hidl_fate;
+    if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+      return false;
+    }
+    hidl_fates->push_back(hidl_fate);
+  }
+  return true;
+}
+
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
     StaLinkLayerStats* hidl_stats) {
@@ -251,6 +668,971 @@
   hidl_stats->timeStampInMs = uptimeMillis();
   return true;
 }
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
+    NanPublishType type) {
+  switch (type) {
+    case NanPublishType::UNSOLICITED:
+      return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+    case NanPublishType::SOLICITED:
+      return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+    case NanPublishType::UNSOLICITED_SOLICITED:
+      return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+  };
+  CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+  switch (type) {
+    case NanTxType::BROADCAST:
+      return legacy_hal::NAN_TX_TYPE_BROADCAST;
+    case NanTxType::UNICAST:
+      return legacy_hal::NAN_TX_TYPE_UNICAST;
+  };
+  CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+  switch (type) {
+    case NanMatchAlg::MATCH_ONCE:
+      return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+    case NanMatchAlg::MATCH_CONTINUOUS:
+      return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+    case NanMatchAlg::MATCH_NEVER:
+      return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+  };
+  CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
+    NanSubscribeType type) {
+  switch (type) {
+    case NanSubscribeType::ACTIVE:
+      return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+    case NanSubscribeType::PASSIVE:
+      return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+  };
+  CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+  switch (type) {
+    case NanSrfType::BLOOM_FILTER:
+      return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+    case NanSrfType::PARTIAL_MAC_ADDR:
+      return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+  };
+  CHECK(false);
+}
+
+legacy_hal::NanSRFIncludeType convertHidlNanSrfIncludeTypeToLegacy(
+    NanSrfIncludeType type) {
+  switch (type) {
+    case NanSrfIncludeType::DO_NOT_RESPOND:
+      return legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+    case NanSrfIncludeType::RESPOND:
+      return legacy_hal::NAN_SRF_INCLUDE_RESPOND;
+  };
+  CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(
+    legacy_hal::NanStatusType /* type */) {
+  // TODO: The |NanStatusType| has changed in legacy HAL and no longer in sync
+  // with the HIDL interface.
+  return NanStatusType::SUCCESS;
+}
+
+NanResponseType convertLegacyNanResponseTypeToHidl(
+    legacy_hal::NanResponseType type) {
+  switch (type) {
+    case legacy_hal::NAN_RESPONSE_ENABLED:
+      return NanResponseType::ENABLED;
+    case legacy_hal::NAN_RESPONSE_DISABLED:
+      return NanResponseType::DISABLED;
+    case legacy_hal::NAN_RESPONSE_PUBLISH:
+      return NanResponseType::PUBLISH;
+    case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL:
+      return NanResponseType::PUBLISH_CANCEL;
+    case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP:
+      return NanResponseType::TRANSMIT_FOLLOWUP;
+    case legacy_hal::NAN_RESPONSE_SUBSCRIBE:
+      return NanResponseType::SUBSCRIBE;
+    case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL:
+      return NanResponseType::SUBSCRIBE_CANCEL;
+    case legacy_hal::NAN_RESPONSE_STATS:
+      // Not present in HIDL. Is going to be deprecated in legacy HAL as well.
+      CHECK(0);
+    case legacy_hal::NAN_RESPONSE_CONFIG:
+      return NanResponseType::CONFIG;
+    case legacy_hal::NAN_RESPONSE_TCA:
+      // Not present in HIDL. Is going to be deprecated in legacy HAL as well.
+      CHECK(0);
+    case legacy_hal::NAN_RESPONSE_ERROR:
+      return NanResponseType::ERROR;
+    case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+      return NanResponseType::BEACON_SDF_PAYLOAD;
+    case legacy_hal::NAN_GET_CAPABILITIES:
+      return NanResponseType::GET_CAPABILITIES;
+    case legacy_hal::NAN_DP_INTERFACE_CREATE:
+      return NanResponseType::DP_INTERFACE_CREATE;
+    case legacy_hal::NAN_DP_INTERFACE_DELETE:
+      return NanResponseType::DP_INTERFACE_DELETE;
+    case legacy_hal::NAN_DP_INITIATOR_RESPONSE:
+      return NanResponseType::DP_INITIATOR_RESPONSE;
+    case legacy_hal::NAN_DP_RESPONDER_RESPONSE:
+      return NanResponseType::DP_RESPONDER_RESPONSE;
+    case legacy_hal::NAN_DP_END:
+      return NanResponseType::DP_END;
+  };
+  CHECK(false) << "Unknown legacy type: " << type;
+}
+
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request) {
+  if (!legacy_request) {
+    return false;
+  }
+  legacy_request->master_pref = hidl_request.masterPref;
+  legacy_request->cluster_low = hidl_request.clusterLow;
+  legacy_request->cluster_high = hidl_request.clusterHigh;
+  legacy_request->config_support_5g = hidl_request.validSupport5gVal;
+  legacy_request->support_5g_val = hidl_request.support5gVal;
+  legacy_request->config_sid_beacon = hidl_request.validSidBeaconVal;
+  legacy_request->sid_beacon_val = hidl_request.sidBeaconVal;
+  legacy_request->config_2dot4g_rssi_close =
+      hidl_request.valid2dot4gRssiCloseVal;
+  legacy_request->rssi_close_2dot4g_val = hidl_request.rssiClose2dot4gVal;
+  legacy_request->config_2dot4g_rssi_middle =
+      hidl_request.valid2dot4gRssiMiddleVal;
+  legacy_request->rssi_middle_2dot4g_val = hidl_request.rssiMiddle2dot4gVal;
+  legacy_request->config_2dot4g_rssi_proximity =
+      hidl_request.valid2dot4gRssiProximityVal;
+  legacy_request->rssi_proximity_2dot4g_val =
+      hidl_request.rssiProximity2dot4gVal;
+  legacy_request->config_hop_count_limit = hidl_request.validHopCountLimitVal;
+  legacy_request->hop_count_limit_val = hidl_request.hopCountLimitVal;
+  legacy_request->config_2dot4g_support = hidl_request.valid2dot4gSupportVal;
+  legacy_request->support_2dot4g_val = hidl_request.support2dot4gVal;
+  legacy_request->config_2dot4g_beacons = hidl_request.valid2dot4gBeaconsVal;
+  legacy_request->beacon_2dot4g_val = hidl_request.beacon2dot4gVal;
+  legacy_request->config_2dot4g_sdf = hidl_request.valid2dot4gSdfVal;
+  legacy_request->sdf_2dot4g_val = hidl_request.sdf2dot4gVal;
+  legacy_request->config_5g_beacons = hidl_request.valid5gBeaconsVal;
+  legacy_request->beacon_5g_val = hidl_request.beacon5gVal;
+  legacy_request->config_5g_sdf = hidl_request.valid5gSdfVal;
+  legacy_request->sdf_5g_val = hidl_request.sdf5gVal;
+  legacy_request->config_5g_rssi_close = hidl_request.valid5gRssiCloseVal;
+  legacy_request->rssi_close_5g_val = hidl_request.rssiClose5gVal;
+  legacy_request->config_5g_rssi_middle = hidl_request.valid5gRssiMiddleVal;
+  legacy_request->rssi_middle_5g_val = hidl_request.rssiMiddle5gVal;
+  legacy_request->config_5g_rssi_close_proximity =
+      hidl_request.valid5gRssiCloseProximityVal;
+  legacy_request->rssi_close_proximity_5g_val =
+      hidl_request.rssiCloseProximity5gVal;
+  legacy_request->config_rssi_window_size = hidl_request.validRssiWindowSizeVal;
+  legacy_request->rssi_window_size_val = hidl_request.rssiWindowSizeVal;
+  legacy_request->config_oui = hidl_request.validOuiVal;
+  legacy_request->oui_val = hidl_request.ouiVal;
+  legacy_request->config_intf_addr = hidl_request.validIntfAddrVal;
+  CHECK(hidl_request.intfAddrVal.size() ==
+        sizeof(legacy_request->intf_addr_val));
+  memcpy(legacy_request->intf_addr_val,
+         hidl_request.intfAddrVal.data(),
+         hidl_request.intfAddrVal.size());
+  legacy_request->config_cluster_attribute_val =
+      hidl_request.configClusterAttributeVal;
+  legacy_request->config_scan_params = hidl_request.validScanParamsVal;
+  if (hidl_request.scanParamsVal.dwellTime.size() >
+      sizeof(legacy_request->scan_params_val.dwell_time)) {
+    return false;
+  }
+  memcpy(legacy_request->scan_params_val.dwell_time,
+         hidl_request.scanParamsVal.dwellTime.data(),
+         hidl_request.scanParamsVal.dwellTime.size());
+  if (hidl_request.scanParamsVal.scanPeriod.size() >
+      sizeof(legacy_request->scan_params_val.scan_period)) {
+    return false;
+  }
+  memcpy(legacy_request->scan_params_val.scan_period,
+         hidl_request.scanParamsVal.scanPeriod.data(),
+         hidl_request.scanParamsVal.scanPeriod.size());
+  legacy_request->config_random_factor_force =
+      hidl_request.validRandomFactorForceVal;
+  legacy_request->random_factor_force_val = hidl_request.randomFactorForceVal;
+  legacy_request->config_hop_count_force = hidl_request.validHopCountLimitVal;
+  legacy_request->hop_count_force_val = hidl_request.hopCountLimitVal;
+  legacy_request->config_24g_channel = hidl_request.valid24gChannelVal;
+  legacy_request->channel_24g_val = hidl_request.channel24gVal;
+  legacy_request->config_5g_channel = hidl_request.valid5gChannelVal;
+  legacy_request->channel_5g_val = hidl_request.channel5gVal;
+  return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request) {
+  if (!legacy_request) {
+    return false;
+  }
+  legacy_request->publish_id = hidl_request.publishId;
+  legacy_request->ttl = hidl_request.ttl;
+  legacy_request->period = hidl_request.period;
+  legacy_request->publish_type =
+      convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+  legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+  legacy_request->publish_count = hidl_request.publishCount;
+  if (hidl_request.serviceName.size() > sizeof(legacy_request->service_name)) {
+    return false;
+  }
+  legacy_request->service_name_len = hidl_request.serviceName.size();
+  memcpy(legacy_request->service_name,
+         hidl_request.serviceName.c_str(),
+         hidl_request.serviceName.size());
+  legacy_request->publish_match_indicator =
+      convertHidlNanMatchAlgToLegacy(hidl_request.publishMatchIndicator);
+  if (hidl_request.serviceSpecificInfo.size() >
+      sizeof(legacy_request->service_specific_info)) {
+    return false;
+  }
+  legacy_request->service_specific_info_len =
+      hidl_request.serviceSpecificInfo.size();
+  memcpy(legacy_request->service_specific_info,
+         hidl_request.serviceSpecificInfo.data(),
+         hidl_request.serviceSpecificInfo.size());
+  if (hidl_request.rxMatchFilter.size() >
+      sizeof(legacy_request->rx_match_filter)) {
+    return false;
+  }
+  legacy_request->rx_match_filter_len = hidl_request.rxMatchFilter.size();
+  memcpy(legacy_request->rx_match_filter,
+         hidl_request.rxMatchFilter.data(),
+         hidl_request.rxMatchFilter.size());
+  if (hidl_request.txMatchFilter.size() >
+      sizeof(legacy_request->tx_match_filter)) {
+    return false;
+  }
+  legacy_request->tx_match_filter_len = hidl_request.txMatchFilter.size();
+  memcpy(legacy_request->tx_match_filter,
+         hidl_request.txMatchFilter.data(),
+         hidl_request.txMatchFilter.size());
+  legacy_request->rssi_threshold_flag = hidl_request.useRssiThreshold;
+  legacy_request->connmap = hidl_request.connmap;
+  legacy_request->recv_indication_cfg = hidl_request.recvIndicationCfg;
+  return true;
+}
+
+bool convertHidlNanPublishCancelRequestToLegacy(
+    const NanPublishCancelRequest& hidl_request,
+    legacy_hal::NanPublishCancelRequest* legacy_request) {
+  legacy_request->publish_id = hidl_request.publishId;
+  return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request) {
+  if (!legacy_request) {
+    return false;
+  }
+  legacy_request->subscribe_id = hidl_request.subscribeId;
+  legacy_request->ttl = hidl_request.ttl;
+  legacy_request->period = hidl_request.period;
+  legacy_request->subscribe_type =
+      convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+  legacy_request->serviceResponseFilter =
+      convertHidlNanSrfTypeToLegacy(hidl_request.serviceResponseFilter);
+  legacy_request->serviceResponseInclude =
+      convertHidlNanSrfIncludeTypeToLegacy(hidl_request.serviceResponseInclude);
+  legacy_request->useServiceResponseFilter =
+      hidl_request.shouldUseServiceResponseFilter
+          ? legacy_hal::NAN_USE_SRF
+          : legacy_hal::NAN_DO_NOT_USE_SRF;
+  legacy_request->ssiRequiredForMatchIndication =
+      hidl_request.isSsiRequiredForMatchIndication
+          ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+          : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+  legacy_request->subscribe_match_indicator =
+      convertHidlNanMatchAlgToLegacy(hidl_request.subscribeMatchIndicator);
+  legacy_request->subscribe_count = hidl_request.subscribeCount;
+  if (hidl_request.serviceName.size() > sizeof(legacy_request->service_name)) {
+    return false;
+  }
+  legacy_request->service_name_len = hidl_request.serviceName.size();
+  memcpy(legacy_request->service_name,
+         hidl_request.serviceName.c_str(),
+         hidl_request.serviceName.size());
+  if (hidl_request.serviceSpecificInfo.size() >
+      sizeof(legacy_request->service_specific_info)) {
+    return false;
+  }
+  legacy_request->service_specific_info_len =
+      hidl_request.serviceSpecificInfo.size();
+  memcpy(legacy_request->service_specific_info,
+         hidl_request.serviceSpecificInfo.data(),
+         hidl_request.serviceSpecificInfo.size());
+  if (hidl_request.rxMatchFilter.size() >
+      sizeof(legacy_request->rx_match_filter)) {
+    return false;
+  }
+  legacy_request->rx_match_filter_len = hidl_request.rxMatchFilter.size();
+  memcpy(legacy_request->rx_match_filter,
+         hidl_request.rxMatchFilter.data(),
+         hidl_request.rxMatchFilter.size());
+  if (hidl_request.txMatchFilter.size() >
+      sizeof(legacy_request->tx_match_filter)) {
+    return false;
+  }
+  legacy_request->tx_match_filter_len = hidl_request.txMatchFilter.size();
+  memcpy(legacy_request->tx_match_filter,
+         hidl_request.txMatchFilter.data(),
+         hidl_request.txMatchFilter.size());
+  legacy_request->rssi_threshold_flag = hidl_request.useRssiThreshold;
+  legacy_request->connmap = hidl_request.connmap;
+  if (hidl_request.intfAddr.size() > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+    return false;
+  }
+  legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+  for (uint32_t i = 0; i < hidl_request.intfAddr.size(); i++) {
+    CHECK(hidl_request.intfAddr[i].size() ==
+          sizeof(legacy_request->intf_addr[i]));
+    memcpy(legacy_request->intf_addr[i],
+           hidl_request.intfAddr[i].data(),
+           hidl_request.intfAddr[i].size());
+  }
+  legacy_request->recv_indication_cfg = hidl_request.recvIndicationCfg;
+  return true;
+}
+
+bool convertHidlNanSubscribeCancelRequestToLegacy(
+    const NanSubscribeCancelRequest& /* hidl_request */,
+    legacy_hal::NanSubscribeCancelRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& /* hidl_request */,
+    legacy_hal::NanTransmitFollowupRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& /* hidl_request */,
+    legacy_hal::NanConfigRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertHidlNanBeaconSdfPayloadRequestToLegacy(
+    const NanBeaconSdfPayloadRequest& /* hidl_request */,
+    legacy_hal::NanBeaconSdfPayloadRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanDataPathInitiatorRequest& /* hidl_request */,
+    legacy_hal::NanDataPathInitiatorRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanDataPathIndicationResponse& /* hidl_response */,
+    legacy_hal::NanDataPathIndicationResponse* /* legacy_response */) {
+  return false;
+}
+
+bool convertHidlNanDataPathEndRequestToLegacy(
+    const NanDataPathEndRequest& /* hidl_request */,
+    legacy_hal::NanDataPathEndRequest* /* legacy_request */) {
+  return false;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    NanResponseMsgHeader* hidl_response) {
+  if (!hidl_response) {
+    return false;
+  }
+  hidl_response->status =
+      convertLegacyNanStatusTypeToHidl(legacy_response.status);
+  hidl_response->value = legacy_response.value;
+  hidl_response->responseType =
+      convertLegacyNanResponseTypeToHidl(legacy_response.response_type);
+  return true;
+}
+
+bool convertLegacyNanPublishResponseToHidl(
+    const legacy_hal::NanPublishResponse& /* legacy_response */,
+    NanPublishResponse* /* hidl_response */) {
+  return false;
+}
+
+bool convertLegacyNanSubscribeResponseToHidl(
+    const legacy_hal::NanSubscribeResponse& /* legacy_response */,
+    NanSubscribeResponse* /* hidl_response */) {
+  return false;
+}
+
+bool convertLegacyNanDataPathResponseToHidl(
+    const legacy_hal::NanDataPathRequestResponse& /* legacy_response */,
+    NanDataPathResponse* /* hidl_response */) {
+  return false;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& /* legacy_response */,
+    NanCapabilitiesResponse* /* hidl_response */) {
+  return false;
+}
+
+bool convertLegacyNanPublishTerminatedIndToHidl(
+    const legacy_hal::NanPublishTerminatedInd& /* legacy_ind */,
+    NanPublishTerminatedInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanMatchIndToHidl(
+    const legacy_hal::NanMatchInd& /* legacy_ind */,
+    NanMatchInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanMatchExpiredIndToHidl(
+    const legacy_hal::NanMatchExpiredInd& /* legacy_ind */,
+    NanMatchExpiredInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanSubscribeTerminatedIndToHidl(
+    const legacy_hal::NanSubscribeTerminatedInd& /* legacy_ind */,
+    NanSubscribeTerminatedInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& /* legacy_ind */,
+    NanFollowupInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanDiscEngEventIndToHidl(
+    const legacy_hal::NanDiscEngEventInd& /* legacy_ind */,
+    NanDiscEngEventInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanDisabledIndToHidl(
+    const legacy_hal::NanDisabledInd& /* legacy_ind */,
+    NanDisabledInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanBeaconSdfPayloadIndToHidl(
+    const legacy_hal::NanBeaconSdfPayloadInd& /* legacy_ind */,
+    NanBeaconSdfPayloadInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& /* legacy_ind */,
+    NanDataPathRequestInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& /* legacy_ind */,
+    NanDataPathConfirmInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanDataPathEndIndToHidl(
+    const legacy_hal::NanDataPathEndInd& /* legacy_ind */,
+    NanDataPathEndInd* /* hidl_ind */) {
+  return false;
+}
+
+bool convertLegacyNanTransmitFollowupIndToHidl(
+    const legacy_hal::NanTransmitFollowupInd& /* legacy_ind */,
+    NanTransmitFollowupInd* /* hidl_ind */) {
+  return false;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+  switch (type) {
+    case RttType::ONE_SIDED:
+      return legacy_hal::RTT_TYPE_1_SIDED;
+    case RttType::TWO_SIDED:
+      return legacy_hal::RTT_TYPE_2_SIDED;
+  };
+  CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+  switch (type) {
+    case legacy_hal::RTT_TYPE_1_SIDED:
+      return RttType::ONE_SIDED;
+    case legacy_hal::RTT_TYPE_2_SIDED:
+      return RttType::TWO_SIDED;
+  };
+  CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+  switch (type) {
+    case RttPeerType::AP:
+      return legacy_hal::RTT_PEER_AP;
+    case RttPeerType::STA:
+      return legacy_hal::RTT_PEER_STA;
+    case RttPeerType::P2P_GO:
+      return legacy_hal::RTT_PEER_P2P_GO;
+    case RttPeerType::P2P_CLIENT:
+      return legacy_hal::RTT_PEER_P2P_CLIENT;
+    case RttPeerType::NAN:
+      return legacy_hal::RTT_PEER_NAN;
+  };
+  CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
+    WifiChannelWidthInMhz type) {
+  switch (type) {
+    case WifiChannelWidthInMhz::WIDTH_20:
+      return legacy_hal::WIFI_CHAN_WIDTH_20;
+    case WifiChannelWidthInMhz::WIDTH_40:
+      return legacy_hal::WIFI_CHAN_WIDTH_40;
+    case WifiChannelWidthInMhz::WIDTH_80:
+      return legacy_hal::WIFI_CHAN_WIDTH_80;
+    case WifiChannelWidthInMhz::WIDTH_160:
+      return legacy_hal::WIFI_CHAN_WIDTH_160;
+    case WifiChannelWidthInMhz::WIDTH_80P80:
+      return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+    case WifiChannelWidthInMhz::WIDTH_5:
+      return legacy_hal::WIFI_CHAN_WIDTH_5;
+    case WifiChannelWidthInMhz::WIDTH_10:
+      return legacy_hal::WIFI_CHAN_WIDTH_10;
+    case WifiChannelWidthInMhz::WIDTH_INVALID:
+      return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+  };
+  CHECK(false);
+}
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+    legacy_hal::wifi_channel_width type) {
+  switch (type) {
+    case legacy_hal::WIFI_CHAN_WIDTH_20:
+      return WifiChannelWidthInMhz::WIDTH_20;
+    case legacy_hal::WIFI_CHAN_WIDTH_40:
+      return WifiChannelWidthInMhz::WIDTH_40;
+    case legacy_hal::WIFI_CHAN_WIDTH_80:
+      return WifiChannelWidthInMhz::WIDTH_80;
+    case legacy_hal::WIFI_CHAN_WIDTH_160:
+      return WifiChannelWidthInMhz::WIDTH_160;
+    case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+      return WifiChannelWidthInMhz::WIDTH_80P80;
+    case legacy_hal::WIFI_CHAN_WIDTH_5:
+      return WifiChannelWidthInMhz::WIDTH_5;
+    case legacy_hal::WIFI_CHAN_WIDTH_10:
+      return WifiChannelWidthInMhz::WIDTH_10;
+    case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
+      return WifiChannelWidthInMhz::WIDTH_INVALID;
+  };
+  CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+  switch (type) {
+    case RttPreamble::LEGACY:
+      return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+    case RttPreamble::HT:
+      return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+    case RttPreamble::VHT:
+      return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+  };
+  CHECK(false);
+}
+
+RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+  switch (type) {
+    case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+      return RttPreamble::LEGACY;
+    case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+      return RttPreamble::HT;
+    case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+      return RttPreamble::VHT;
+  };
+  CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+  switch (type) {
+    case RttBw::BW_5MHZ:
+      return legacy_hal::WIFI_RTT_BW_5;
+    case RttBw::BW_10MHZ:
+      return legacy_hal::WIFI_RTT_BW_10;
+    case RttBw::BW_20MHZ:
+      return legacy_hal::WIFI_RTT_BW_20;
+    case RttBw::BW_40MHZ:
+      return legacy_hal::WIFI_RTT_BW_40;
+    case RttBw::BW_80MHZ:
+      return legacy_hal::WIFI_RTT_BW_80;
+    case RttBw::BW_160MHZ:
+      return legacy_hal::WIFI_RTT_BW_160;
+  };
+  CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+  switch (type) {
+    case legacy_hal::WIFI_RTT_BW_5:
+      return RttBw::BW_5MHZ;
+    case legacy_hal::WIFI_RTT_BW_10:
+      return RttBw::BW_10MHZ;
+    case legacy_hal::WIFI_RTT_BW_20:
+      return RttBw::BW_20MHZ;
+    case legacy_hal::WIFI_RTT_BW_40:
+      return RttBw::BW_40MHZ;
+    case legacy_hal::WIFI_RTT_BW_80:
+      return RttBw::BW_80MHZ;
+    case legacy_hal::WIFI_RTT_BW_160:
+      return RttBw::BW_160MHZ;
+  };
+  CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
+    RttMotionPattern type) {
+  switch (type) {
+    case RttMotionPattern::NOT_EXPECTED:
+      return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+    case RttMotionPattern::EXPECTED:
+      return legacy_hal::WIFI_MOTION_EXPECTED;
+    case RttMotionPattern::UNKNOWN:
+      return legacy_hal::WIFI_MOTION_UNKNOWN;
+  };
+  CHECK(false);
+}
+
+WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+  switch (preamble) {
+    case 0:
+      return WifiRatePreamble::OFDM;
+    case 1:
+      return WifiRatePreamble::CCK;
+    case 2:
+      return WifiRatePreamble::HT;
+    case 3:
+      return WifiRatePreamble::VHT;
+    default:
+      return WifiRatePreamble::RESERVED;
+  };
+  CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+  switch (nss) {
+    case 0:
+      return WifiRateNss::NSS_1x1;
+    case 1:
+      return WifiRateNss::NSS_2x2;
+    case 2:
+      return WifiRateNss::NSS_3x3;
+    case 3:
+      return WifiRateNss::NSS_4x4;
+  };
+  CHECK(false) << "Unknown legacy nss: " << nss;
+  return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+  switch (status) {
+    case legacy_hal::RTT_STATUS_SUCCESS:
+      return RttStatus::SUCCESS;
+    case legacy_hal::RTT_STATUS_FAILURE:
+      return RttStatus::FAILURE;
+    case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+      return RttStatus::FAIL_NO_RSP;
+    case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+      return RttStatus::FAIL_REJECTED;
+    case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+      return RttStatus::FAIL_NOT_SCHEDULED_YET;
+    case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+      return RttStatus::FAIL_TM_TIMEOUT;
+    case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+      return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+    case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+      return RttStatus::FAIL_NO_CAPABILITY;
+    case legacy_hal::RTT_STATUS_ABORTED:
+      return RttStatus::ABORTED;
+    case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+      return RttStatus::FAIL_INVALID_TS;
+    case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+      return RttStatus::FAIL_PROTOCOL;
+    case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+      return RttStatus::FAIL_SCHEDULE;
+    case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+      return RttStatus::FAIL_BUSY_TRY_LATER;
+    case legacy_hal::RTT_STATUS_INVALID_REQ:
+      return RttStatus::INVALID_REQ;
+    case legacy_hal::RTT_STATUS_NO_WIFI:
+      return RttStatus::NO_WIFI;
+    case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+      return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+  };
+  CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info) {
+  if (!legacy_info) {
+    return false;
+  }
+  legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+  legacy_info->center_freq = hidl_info.centerFreq;
+  legacy_info->center_freq0 = hidl_info.centerFreq0;
+  legacy_info->center_freq1 = hidl_info.centerFreq1;
+  return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(
+    const legacy_hal::wifi_channel_info& legacy_info,
+    WifiChannelInfo* hidl_info) {
+  if (!hidl_info) {
+    return false;
+  }
+  hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+  hidl_info->centerFreq = legacy_info.center_freq;
+  hidl_info->centerFreq0 = legacy_info.center_freq0;
+  hidl_info->centerFreq1 = legacy_info.center_freq1;
+  return true;
+}
+
+bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+                                  legacy_hal::wifi_rtt_config* legacy_config) {
+  if (!legacy_config) {
+    return false;
+  }
+  CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+  memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
+  legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+  legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+  if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
+                                          &legacy_config->channel)) {
+    return false;
+  }
+  legacy_config->burst_period = hidl_config.burstPeriod;
+  legacy_config->num_burst = hidl_config.numBurst;
+  legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+  legacy_config->num_retries_per_rtt_frame = hidl_config.numRetriesPerRttFrame;
+  legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+  legacy_config->LCI_request = hidl_config.mustRequestLci;
+  legacy_config->LCR_request = hidl_config.mustRequestLcr;
+  legacy_config->burst_duration = hidl_config.burstDuration;
+  legacy_config->preamble =
+      convertHidlRttPreambleToLegacy(hidl_config.preamble);
+  legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+  return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+  if (!legacy_configs) {
+    return false;
+  }
+  legacy_configs->clear();
+  for (const auto& hidl_config : hidl_configs) {
+    legacy_hal::wifi_rtt_config legacy_config;
+    if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+      return false;
+    }
+    legacy_configs->push_back(legacy_config);
+  }
+  return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info) {
+  if (!legacy_info) {
+    return false;
+  }
+  legacy_info->latitude = hidl_info.latitude;
+  legacy_info->longitude = hidl_info.longitude;
+  legacy_info->altitude = hidl_info.altitude;
+  legacy_info->latitude_unc = hidl_info.latitudeUnc;
+  legacy_info->longitude_unc = hidl_info.longitudeUnc;
+  legacy_info->altitude_unc = hidl_info.altitudeUnc;
+  legacy_info->motion_pattern =
+      convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+  legacy_info->floor = hidl_info.floor;
+  legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+  legacy_info->height_unc = hidl_info.heightUnc;
+  return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info) {
+  if (!legacy_info) {
+    return false;
+  }
+  CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+  memcpy(legacy_info->country_code,
+         hidl_info.countryCode.data(),
+         hidl_info.countryCode.size());
+  if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+    return false;
+  }
+  legacy_info->length = hidl_info.civicInfo.size();
+  memcpy(legacy_info->civic_info,
+         hidl_info.civicInfo.c_str(),
+         hidl_info.civicInfo.size());
+  return true;
+}
+
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder) {
+  if (!legacy_responder) {
+    return false;
+  }
+  if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
+                                          &legacy_responder->channel)) {
+    return false;
+  }
+  legacy_responder->preamble =
+      convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+  return true;
+}
+
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder) {
+  if (!hidl_responder) {
+    return false;
+  }
+  if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
+                                          &hidl_responder->channel)) {
+    return false;
+  }
+  hidl_responder->preamble =
+      convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+  return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities) {
+  if (!hidl_capabilities) {
+    return false;
+  }
+  hidl_capabilities->rttOneSidedSupported =
+      legacy_capabilities.rtt_one_sided_supported;
+  hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+  hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+  hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+  hidl_capabilities->responderSupported =
+      legacy_capabilities.responder_supported;
+  for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
+                          legacy_hal::WIFI_RTT_PREAMBLE_HT,
+                          legacy_hal::WIFI_RTT_PREAMBLE_VHT}) {
+    if (legacy_capabilities.preamble_support & flag) {
+      hidl_capabilities->preambleSupport |=
+          static_cast<std::underlying_type<RttPreamble>::type>(
+              convertLegacyRttPreambleToHidl(flag));
+    }
+  }
+  for (const auto flag : {legacy_hal::WIFI_RTT_BW_5,
+                          legacy_hal::WIFI_RTT_BW_10,
+                          legacy_hal::WIFI_RTT_BW_20,
+                          legacy_hal::WIFI_RTT_BW_40,
+                          legacy_hal::WIFI_RTT_BW_80,
+                          legacy_hal::WIFI_RTT_BW_160}) {
+    if (legacy_capabilities.bw_support & flag) {
+      hidl_capabilities->bwSupport |=
+          static_cast<std::underlying_type<RttBw>::type>(
+              convertLegacyRttBwToHidl(flag));
+    }
+  }
+  hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+  return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     WifiRateInfo* hidl_rate) {
+  if (!hidl_rate) {
+    return false;
+  }
+  hidl_rate->preamble =
+      convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+  hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+  hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+      static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+  hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+  hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+  return true;
+}
+
+bool convertLegacyRttResultToHidl(
+    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+  if (!hidl_result) {
+    return false;
+  }
+  CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+  memcpy(
+      hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
+  hidl_result->burstNum = legacy_result.burst_num;
+  hidl_result->measurementNumber = legacy_result.measurement_number;
+  hidl_result->successNumber = legacy_result.success_number;
+  hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+  hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+  hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+  hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+  hidl_result->rssi = legacy_result.rssi;
+  hidl_result->rssiSpread = legacy_result.rssi_spread;
+  if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
+                                       &hidl_result->txRate)) {
+    return false;
+  }
+  if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
+                                       &hidl_result->rxRate)) {
+    return false;
+  }
+  hidl_result->rtt = legacy_result.rtt;
+  hidl_result->rttSd = legacy_result.rtt_sd;
+  hidl_result->rttSpread = legacy_result.rtt_spread;
+  hidl_result->distanceInMm = legacy_result.distance_mm;
+  hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+  hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+  hidl_result->timeStampInUs = legacy_result.ts;
+  hidl_result->burstDurationInMs = legacy_result.burst_duration;
+  hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+  if (!convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+    return false;
+  }
+  if (!convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+    return false;
+  }
+  return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results) {
+  if (!hidl_results) {
+    return false;
+  }
+  hidl_results->clear();
+  for (const auto legacy_result : legacy_results) {
+    RttResult hidl_result;
+    if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+      return false;
+    }
+    hidl_results->push_back(hidl_result);
+  }
+  return true;
+}
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/wifi/1.0/default/hidl_struct_util.h b/wifi/1.0/default/hidl_struct_util.h
index 6c91e03..3ff94fd 100644
--- a/wifi/1.0/default/hidl_struct_util.h
+++ b/wifi/1.0/default/hidl_struct_util.h
@@ -36,29 +36,160 @@
 namespace implementation {
 namespace hidl_struct_util {
 
-// Convert hidl gscan params to legacy gscan params.
-bool convertHidlScanParamsToLegacy(
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_logger_feature_set, uint32_t* hidl_caps);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint32_t legacy_feature_set,
+    uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlGscanBandToLegacy(StaBackgroundScanBand band);
+bool convertHidlGscanParamsToLegacy(
     const StaBackgroundScanParameters& hidl_scan_params,
     legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
-// Convert the blob of packed IE elements to vector of
-// |WifiInformationElement| structures.
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob,
-                               uint32_t ie_blob_len,
-                               std::vector<WifiInformationElement>* hidl_ies);
 // |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
 // Information Elements (IEs)
-bool convertLegacyScanResultToHidl(
+bool convertLegacyGscanResultToHidl(
     const legacy_hal::wifi_scan_result& legacy_scan_result,
     bool has_ie_data,
     StaScanResult* hidl_scan_result);
 // |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedScanResultsToHidl(
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
     const std::vector<legacy_hal::wifi_cached_scan_results>&
         legacy_cached_scan_results,
     std::vector<StaScanData>* hidl_scan_datas);
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
     StaLinkLayerStats* hidl_stats);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanPublishCancelRequestToLegacy(
+    const NanPublishCancelRequest& hidl_request,
+    legacy_hal::NanPublishCancelRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanSubscribeCancelRequestToLegacy(
+    const NanSubscribeCancelRequest& hidl_request,
+    legacy_hal::NanSubscribeCancelRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& hidl_request,
+    legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& hidl_request,
+    legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanBeaconSdfPayloadRequestToLegacy(
+    const NanBeaconSdfPayloadRequest& hidl_request,
+    legacy_hal::NanBeaconSdfPayloadRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanDataPathInitiatorRequest& hidl_request,
+    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanDataPathIndicationResponse& hidl_response,
+    legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertHidlNanDataPathEndRequestToLegacy(
+    const NanDataPathEndRequest& hidl_request,
+    legacy_hal::NanDataPathEndRequest* legacy_request);
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    NanResponseMsgHeader* hidl_response);
+bool convertLegacyNanPublishResponseToHidl(
+    const legacy_hal::NanPublishResponse& legacy_response,
+    NanPublishResponse* hidl_response);
+bool convertLegacyNanSubscribeResponseToHidl(
+    const legacy_hal::NanSubscribeResponse& legacy_response,
+    NanSubscribeResponse* hidl_response);
+bool convertLegacyNanDataPathResponseToHidl(
+    const legacy_hal::NanDataPathRequestResponse& legacy_response,
+    NanDataPathResponse* hidl_response);
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& legacy_response,
+    NanCapabilitiesResponse* hidl_response);
+bool convertLegacyNanPublishTerminatedIndToHidl(
+    const legacy_hal::NanPublishTerminatedInd& legacy_ind,
+    NanPublishTerminatedInd* hidl_ind);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* hidl_ind);
+bool convertLegacyNanMatchExpiredIndToHidl(
+    const legacy_hal::NanMatchExpiredInd& legacy_ind,
+    NanMatchExpiredInd* hidl_ind);
+bool convertLegacyNanSubscribeTerminatedIndToHidl(
+    const legacy_hal::NanSubscribeTerminatedInd& legacy_ind,
+    NanSubscribeTerminatedInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& legacy_ind, NanFollowupInd* hidl_ind);
+bool convertLegacyNanDiscEngEventIndToHidl(
+    const legacy_hal::NanDiscEngEventInd& legacy_ind,
+    NanDiscEngEventInd* hidl_ind);
+bool convertLegacyNanDisabledIndToHidl(
+    const legacy_hal::NanDisabledInd& legacy_ind, NanDisabledInd* hidl_ind);
+bool convertLegacyNanBeaconSdfPayloadIndToHidl(
+    const legacy_hal::NanBeaconSdfPayloadInd& legacy_ind,
+    NanBeaconSdfPayloadInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& legacy_ind,
+    NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+    NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathEndIndToHidl(
+    const legacy_hal::NanDataPathEndInd& legacy_ind,
+    NanDataPathEndInd* hidl_ind);
+bool convertLegacyNanTransmitFollowupIndToHidl(
+    const legacy_hal::NanTransmitFollowupInd& legacy_ind,
+    NanTransmitFollowupInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results);
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.0/default/wifi.cpp
index 19f7e53..30adcc0 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.0/default/wifi.cpp
@@ -34,6 +34,7 @@
 
 Wifi::Wifi()
     : legacy_hal_(new legacy_hal::WifiLegacyHal()),
+      mode_controller_(new mode_controller::WifiModeController()),
       run_state_(RunState::STOPPED) {}
 
 bool Wifi::isValid() {
@@ -96,25 +97,29 @@
     return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                             "HAL is stopping");
   }
-
-  LOG(INFO) << "Starting HAL";
-  legacy_hal::wifi_error legacy_status = legacy_hal_->start();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to start Wifi HAL: "
-               << legacyErrorToString(legacy_status);
-    return createWifiStatusFromLegacyError(legacy_status,
-                                           "Failed to start HAL");
+  WifiStatus wifi_status = initializeLegacyHal();
+  if (wifi_status.code == WifiStatusCode::SUCCESS) {
+    // Create the chip instance once the HAL is started.
+    chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_);
+    run_state_ = RunState::STARTED;
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onStart().getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onStart callback";
+      };
+    }
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
+    }
+  } else {
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
+    }
   }
-
-  // Create the chip instance once the HAL is started.
-  chip_ = new WifiChip(kChipId, legacy_hal_);
-  run_state_ = RunState::STARTED;
-  for (const auto& callback : event_callbacks_) {
-    if (!callback->onStart().getStatus().isOk()) {
-      LOG(ERROR) << "Failed to invoke onStart callback";
-    };
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  return wifi_status;
 }
 
 WifiStatus Wifi::stopInternal() {
@@ -124,34 +129,21 @@
     return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                             "HAL is stopping");
   }
-
-  LOG(INFO) << "Stopping HAL";
-  run_state_ = RunState::STOPPING;
-  const auto on_complete_callback_ = [&]() {
-    if (chip_.get()) {
-      chip_->invalidate();
-    }
-    chip_.clear();
-    run_state_ = RunState::STOPPED;
+  WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController();
+  if (wifi_status.code == WifiStatusCode::SUCCESS) {
     for (const auto& callback : event_callbacks_) {
       if (!callback->onStop().getStatus().isOk()) {
         LOG(ERROR) << "Failed to invoke onStop callback";
       };
     }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_->stop(on_complete_callback_);
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to stop Wifi HAL: "
-               << legacyErrorToString(legacy_status);
-    WifiStatus wifi_status =
-        createWifiStatusFromLegacyError(legacy_status, "Failed to stop HAL");
+  } else {
     for (const auto& callback : event_callbacks_) {
-      callback->onFailure(wifi_status);
+      if (!callback->onFailure(wifi_status).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke onFailure callback";
+      }
     }
-    return wifi_status;
   }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  return wifi_status;
 }
 
 std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
@@ -171,6 +163,41 @@
   }
   return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
 }
+
+WifiStatus Wifi::initializeLegacyHal() {
+  LOG(INFO) << "Initializing legacy HAL";
+  legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to initialize legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController() {
+  LOG(INFO) << "Stopping legacy HAL";
+  run_state_ = RunState::STOPPING;
+  const auto on_complete_callback_ = [&]() {
+    if (chip_.get()) {
+      chip_->invalidate();
+    }
+    chip_.clear();
+    run_state_ = RunState::STOPPED;
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_->stop(on_complete_callback_);
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to stop legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  if (!mode_controller_->deinitialize()) {
+    LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+  }
+  return createWifiStatus(WifiStatusCode::SUCCESS);
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace wifi
diff --git a/wifi/1.0/default/wifi.h b/wifi/1.0/default/wifi.h
index 7872303..40d3552 100644
--- a/wifi/1.0/default/wifi.h
+++ b/wifi/1.0/default/wifi.h
@@ -25,6 +25,7 @@
 
 #include "wifi_chip.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
 
 namespace android {
 namespace hardware {
@@ -62,9 +63,13 @@
   std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
   std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
 
+  WifiStatus initializeLegacyHal();
+  WifiStatus stopLegacyHalAndDeinitializeModeController();
+
   // Instance is created in this root level |IWifi| HIDL interface object
   // and shared with all the child HIDL interface objects.
   std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+  std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
   RunState run_state_;
   std::vector<sp<IWifiEventCallback>> event_callbacks_;
   sp<WifiChip> chip_;
diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.0/default/wifi_chip.cpp
index 3ab6052..4f3c192 100644
--- a/wifi/1.0/default/wifi_chip.cpp
+++ b/wifi/1.0/default/wifi_chip.cpp
@@ -17,6 +17,7 @@
 #include <android-base/logging.h>
 
 #include "hidl_return_util.h"
+#include "hidl_struct_util.h"
 #include "wifi_chip.h"
 #include "wifi_status_util.h"
 
@@ -24,6 +25,12 @@
 using android::sp;
 using android::hardware::hidl_vec;
 using android::hardware::hidl_string;
+using android::hardware::wifi::V1_0::IWifiChip;
+using android::hardware::wifi::V1_0::IfaceType;
+
+constexpr uint32_t kStaChipModeId = 0;
+constexpr uint32_t kApChipModeId = 1;
+constexpr uint32_t kInvalidModeId = UINT32_MAX;
 
 template <typename Iface>
 void invalidateAndClear(sp<Iface>& iface) {
@@ -41,9 +48,15 @@
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
-WifiChip::WifiChip(ChipId chip_id,
-                   const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : chip_id_(chip_id), legacy_hal_(legacy_hal), is_valid_(true) {}
+WifiChip::WifiChip(
+    ChipId chip_id,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<mode_controller::WifiModeController> mode_controller)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      is_valid_(true),
+      current_mode_id_(kInvalidModeId) {}
 
 void WifiChip::invalidate() {
   invalidateAndRemoveAllIfaces();
@@ -295,25 +308,101 @@
 }
 
 std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
-  // TODO add implementation
-  return {createWifiStatus(WifiStatusCode::SUCCESS), 0};
+  legacy_hal::wifi_error legacy_status;
+  uint32_t legacy_logger_feature_set;
+  std::tie(legacy_status, legacy_logger_feature_set) =
+      legacy_hal_.lock()->getLoggerSupportedFeatureSet();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), 0};
+  }
+  uint32_t hidl_caps;
+  if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+          legacy_logger_feature_set, &hidl_caps)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
 std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
 WifiChip::getAvailableModesInternal() {
-  // TODO add implementation
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  // The chip combination supported for current devices is fixed for now with
+  // 2 separate modes of operation:
+  // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations
+  // concurrently.
+  // Mode 2 (AP mode): Will support 1 AP iface operations.
+  // TODO (b/32997844): Read this from some device specific flags in the
+  // makefile.
+  // STA mode iface combinations.
+  const IWifiChip::ChipIfaceCombinationLimit
+      sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+  const IWifiChip::ChipIfaceCombinationLimit
+      sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN},
+                                            1};
+  const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = {
+      {sta_chip_iface_combination_limit_1, sta_chip_iface_combination_limit_2}};
+  const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId,
+                                             {sta_chip_iface_combination}};
+  // AP mode iface combinations.
+  const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = {
+      {IfaceType::AP}, 1};
+  const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = {
+      {ap_chip_iface_combination_limit}};
+  const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId,
+                                            {ap_chip_iface_combination}};
+  return {createWifiStatus(WifiStatusCode::SUCCESS),
+          {sta_chip_mode, ap_chip_mode}};
 }
 
-WifiStatus WifiChip::configureChipInternal(uint32_t /* mode_id */) {
-  invalidateAndRemoveAllIfaces();
-  // TODO add implementation
+WifiStatus WifiChip::configureChipInternal(uint32_t mode_id) {
+  if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  if (mode_id == current_mode_id_) {
+    LOG(DEBUG) << "Already in the specified mode " << mode_id;
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+  }
+  // If the chip is already configured in a different mode, stop
+  // the legacy HAL and then start it after firmware mode change.
+  if (current_mode_id_ != kInvalidModeId) {
+    invalidateAndRemoveAllIfaces();
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop([]() {});
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+      LOG(ERROR) << "Failed to stop legacy HAL: "
+                 << legacyErrorToString(legacy_status);
+      // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+      return createWifiStatusFromLegacyError(legacy_status);
+    }
+  }
+  bool success;
+  if (mode_id == kStaChipModeId) {
+    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+  } else {
+    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+  }
+  if (!success) {
+    // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+  }
+  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to start legacy HAL: "
+               << legacyErrorToString(legacy_status);
+    // TODO(b/33038823): Need to invoke onChipReconfigureFailure()
+    return createWifiStatusFromLegacyError(legacy_status);
+  }
+  for (const auto& callback : event_callbacks_) {
+    callback->onChipReconfigured(mode_id);
+  }
+  current_mode_id_ = mode_id;
   return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-  // TODO add implementation
-  return {createWifiStatus(WifiStatusCode::SUCCESS), 0};
+  if (current_mode_id_ == kInvalidModeId) {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
+            current_mode_id_};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
 }
 
 std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
@@ -484,29 +573,61 @@
 
 std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
 WifiChip::getDebugRingBuffersStatusInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  std::vector<legacy_hal::wifi_ring_buffer_status>
+      legacy_ring_buffer_status_vec;
+  std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+      legacy_hal_.lock()->getRingBuffersStatus();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+  if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+          legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS),
+          hidl_ring_buffer_status_vec};
 }
 
 WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
-    const hidl_string& /* ring_name */,
-    WifiDebugRingBufferVerboseLevel /* verbose_level */,
-    uint32_t /* max_interval_in_sec */,
-    uint32_t /* min_data_size_in_bytes */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    const hidl_string& ring_name,
+    WifiDebugRingBufferVerboseLevel verbose_level,
+    uint32_t max_interval_in_sec,
+    uint32_t min_data_size_in_bytes) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startRingBufferLogging(
+          ring_name,
+          static_cast<
+              std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
+              verbose_level),
+          max_interval_in_sec,
+          min_data_size_in_bytes);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
-    const hidl_string& /* ring_name */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    const hidl_string& ring_name) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->getRingBufferData(ring_name);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
 WifiChip::getDebugHostWakeReasonStatsInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::WakeReasonStats legacy_stats;
+  std::tie(legacy_status, legacy_stats) =
+      legacy_hal_.lock()->getWakeReasonStats();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  WifiDebugHostWakeReasonStats hidl_stats;
+  if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
+                                                            &hidl_stats)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
 }
 
 }  // namespace implementation
diff --git a/wifi/1.0/default/wifi_chip.h b/wifi/1.0/default/wifi_chip.h
index c1a7173..764445f 100644
--- a/wifi/1.0/default/wifi_chip.h
+++ b/wifi/1.0/default/wifi_chip.h
@@ -24,6 +24,7 @@
 
 #include "wifi_ap_iface.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
 #include "wifi_nan_iface.h"
 #include "wifi_p2p_iface.h"
 #include "wifi_rtt_controller.h"
@@ -42,8 +43,10 @@
  */
 class WifiChip : public IWifiChip {
  public:
-  WifiChip(ChipId chip_id,
-           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+  WifiChip(
+      ChipId chip_id,
+      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+      const std::weak_ptr<mode_controller::WifiModeController> mode_controller);
   // HIDL does not provide a built-in mechanism to let the server invalidate
   // a HIDL interface object after creation. If any client process holds onto
   // a reference to the object in their context, any method calls on that
@@ -156,6 +159,7 @@
 
   ChipId chip_id_;
   std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+  std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
   std::vector<sp<IWifiChipEventCallback>> event_callbacks_;
   sp<WifiApIface> ap_iface_;
   sp<WifiNanIface> nan_iface_;
@@ -163,6 +167,7 @@
   sp<WifiStaIface> sta_iface_;
   std::vector<sp<WifiRttController>> rtt_controllers_;
   bool is_valid_;
+  uint32_t current_mode_id_;
 
   DISALLOW_COPY_AND_ASSIGN(WifiChip);
 };
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index 560a273..bf61d83 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -18,10 +18,11 @@
 
 #include <android-base/logging.h>
 #include <cutils/properties.h>
-#include <wifi_system/interface_tool.h>
 
 #include "wifi_legacy_hal.h"
 
+using android::wifi_system::InterfaceTool;
+
 namespace android {
 namespace hardware {
 namespace wifi {
@@ -89,16 +90,25 @@
 // Callback to be invoked for link layer stats results.
 std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
     on_link_layer_stats_result_internal_callback;
-void onLinkLayerStatsDataResult(wifi_request_id id,
-                                wifi_iface_stat* iface_stat,
-                                int num_radios,
-                                wifi_radio_stat* radio_stat) {
+void onLinkLayerStatsResult(wifi_request_id id,
+                            wifi_iface_stat* iface_stat,
+                            int num_radios,
+                            wifi_radio_stat* radio_stat) {
   if (on_link_layer_stats_result_internal_callback) {
     on_link_layer_stats_result_internal_callback(
         id, iface_stat, num_radios, radio_stat);
   }
 }
 
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+    on_rssi_threshold_breached_internal_callback;
+void onRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) {
+  if (on_rssi_threshold_breached_internal_callback) {
+    on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+  }
+}
+
 // Callback to be invoked for ring buffer data indication.
 std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
     on_ring_buffer_data_internal_callback;
@@ -241,12 +251,7 @@
       wlan_interface_handle_(nullptr),
       awaiting_event_loop_termination_(false) {}
 
-wifi_error WifiLegacyHal::start() {
-  // Ensure that we're starting in a good state.
-  CHECK(!global_handle_ && !wlan_interface_handle_ &&
-        !awaiting_event_loop_termination_);
-
-  android::wifi_system::InterfaceTool if_tool;
+wifi_error WifiLegacyHal::initialize() {
   // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
   // for now is this function call which we can directly call.
   wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
@@ -254,13 +259,19 @@
     LOG(ERROR) << "Failed to initialize legacy hal function table";
     return WIFI_ERROR_UNKNOWN;
   }
-  if (!if_tool.SetWifiUpState(true)) {
+  return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::start() {
+  // Ensure that we're starting in a good state.
+  CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
+        !wlan_interface_handle_ && !awaiting_event_loop_termination_);
+  if (!iface_tool_.SetWifiUpState(true)) {
     LOG(ERROR) << "Failed to set WiFi interface up";
     return WIFI_ERROR_UNKNOWN;
   }
-
   LOG(INFO) << "Starting legacy HAL";
-  status = global_func_table_.wifi_initialize(&global_handle_);
+  wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
   if (status != WIFI_SUCCESS || !global_handle_) {
     LOG(ERROR) << "Failed to retrieve global handle";
     return status;
@@ -280,10 +291,11 @@
   LOG(INFO) << "Stopping legacy HAL";
   on_stop_complete_internal_callback = [&](wifi_handle handle) {
     CHECK_EQ(global_handle_, handle) << "Handle mismatch";
-    on_stop_complete_user_callback();
     // Invalidate all the internal pointers now that the HAL is
     // stopped.
     invalidate();
+    iface_tool_.SetWifiUpState(false);
+    on_stop_complete_user_callback();
   };
   awaiting_event_loop_termination_ = true;
   global_func_table_.wifi_cleanup(global_handle_, onStopComplete);
@@ -534,11 +546,57 @@
   };
 
   wifi_error status = global_func_table_.wifi_get_link_stats(
-      0, wlan_interface_handle_, {onLinkLayerStatsDataResult});
+      0, wlan_interface_handle_, {onLinkLayerStatsResult});
   on_link_layer_stats_result_internal_callback = nullptr;
   return {status, link_stats};
 }
 
+wifi_error WifiLegacyHal::startRssiMonitoring(
+    wifi_request_id id,
+    int8_t max_rssi,
+    int8_t min_rssi,
+    const on_rssi_threshold_breached_callback&
+        on_threshold_breached_user_callback) {
+  if (on_rssi_threshold_breached_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  on_rssi_threshold_breached_internal_callback =
+      [on_threshold_breached_user_callback](
+          wifi_request_id id, uint8_t* bssid_ptr, int8_t rssi) {
+        if (!bssid_ptr) {
+          return;
+        }
+        std::array<uint8_t, 6> bssid_arr;
+        // |bssid_ptr| pointer is assumed to have 6 bytes for the mac address.
+        std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+        on_threshold_breached_user_callback(id, bssid_arr, rssi);
+      };
+  wifi_error status =
+      global_func_table_.wifi_start_rssi_monitoring(id,
+                                                    wlan_interface_handle_,
+                                                    max_rssi,
+                                                    min_rssi,
+                                                    {onRssiThresholdBreached});
+  if (status != WIFI_SUCCESS) {
+    on_rssi_threshold_breached_internal_callback = nullptr;
+  }
+  return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(wifi_request_id id) {
+  if (!on_rssi_threshold_breached_internal_callback) {
+    return WIFI_ERROR_NOT_AVAILABLE;
+  }
+  wifi_error status =
+      global_func_table_.wifi_stop_rssi_monitoring(id, wlan_interface_handle_);
+  // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+  // other error should be treated as the end of background scan.
+  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+    on_rssi_threshold_breached_internal_callback = nullptr;
+  }
+  return status;
+}
+
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet() {
   uint32_t supported_features;
   wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set(
@@ -697,11 +755,16 @@
   };
 
   std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
-  return global_func_table_.wifi_rtt_range_request(id,
-                                                   wlan_interface_handle_,
-                                                   rtt_configs.size(),
-                                                   rtt_configs_internal.data(),
-                                                   {onRttResults});
+  wifi_error status =
+      global_func_table_.wifi_rtt_range_request(id,
+                                                wlan_interface_handle_,
+                                                rtt_configs.size(),
+                                                rtt_configs_internal.data(),
+                                                {onRttResults});
+  if (status != WIFI_SUCCESS) {
+    on_rtt_results_internal_callback = nullptr;
+  }
+  return status;
 }
 
 wifi_error WifiLegacyHal::cancelRttRangeRequest(
@@ -974,8 +1037,6 @@
   }
   LOG(VERBOSE) << "Legacy HAL event loop terminated";
   awaiting_event_loop_termination_ = false;
-  android::wifi_system::InterfaceTool if_tool;
-  if_tool.SetWifiUpState(false);
 }
 
 std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
@@ -1016,6 +1077,7 @@
   on_gscan_event_internal_callback = nullptr;
   on_gscan_full_result_internal_callback = nullptr;
   on_link_layer_stats_result_internal_callback = nullptr;
+  on_rssi_threshold_breached_internal_callback = nullptr;
   on_ring_buffer_data_internal_callback = nullptr;
   on_rtt_results_internal_callback = nullptr;
   on_nan_notify_response_user_callback = nullptr;
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index 62b773e..b68fa50 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -21,6 +21,8 @@
 #include <thread>
 #include <vector>
 
+#include <wifi_system/interface_tool.h>
+
 namespace android {
 namespace hardware {
 namespace wifi {
@@ -99,6 +101,10 @@
 using on_gscan_results_callback = std::function<void(
     wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
 
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
 // Callback for RTT range request results.
 // Rtt results contain IE info and are hence passed by reference, to
 // preserve the |LCI| and |LCR| pointers. Callee must not retain
@@ -125,7 +131,9 @@
   std::string getP2pIfaceName();
   std::string getStaIfaceName();
 
-  // Initialize the legacy HAL and start the event looper thread.
+  // Initialize the legacy HAL function table.
+  wifi_error initialize();
+  // Start the legacy HAL and the event looper thread.
   wifi_error start();
   // Deinitialize the legacy HAL and stop the event looper thread.
   wifi_error stop(const std::function<void()>& on_complete_callback);
@@ -163,6 +171,13 @@
   wifi_error enableLinkLayerStats(bool debug);
   wifi_error disableLinkLayerStats();
   std::pair<wifi_error, LinkLayerStats> getLinkLayerStats();
+  // RSSI monitor functions.
+  wifi_error startRssiMonitoring(wifi_request_id id,
+                                 int8_t max_rssi,
+                                 int8_t min_rssi,
+                                 const on_rssi_threshold_breached_callback&
+                                     on_threshold_breached_callback);
+  wifi_error stopRssiMonitoring(wifi_request_id id);
   // Logger/debug functions.
   std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet();
   wifi_error startPktFateMonitoring();
@@ -245,6 +260,7 @@
   wifi_interface_handle wlan_interface_handle_;
   // Flag to indicate if we have initiated the cleanup of legacy HAL.
   bool awaiting_event_loop_termination_;
+  wifi_system::InterfaceTool iface_tool_;
 };
 
 }  // namespace legacy_hal
diff --git a/wifi/1.0/default/wifi_mode_controller.cpp b/wifi/1.0/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..42dd9ad
--- /dev/null
+++ b/wifi/1.0/default/wifi_mode_controller.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+  int mode;
+  switch (type) {
+    case IfaceType::AP:
+      mode = DriverTool::kFirmwareModeAp;
+      break;
+    case IfaceType::P2P:
+      mode = DriverTool::kFirmwareModeP2p;
+      break;
+    case IfaceType::NAN:
+      // NAN is exposed in STA mode currently.
+      mode = DriverTool::kFirmwareModeSta;
+      break;
+    case IfaceType::STA:
+      mode = DriverTool::kFirmwareModeSta;
+      break;
+  }
+  return mode;
+}
+}
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_0 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+  return driver_tool_->IsFirmwareModeChangeNeeded(
+      convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+  if (!driver_tool_->LoadDriver()) {
+    LOG(ERROR) << "Failed to load WiFi driver";
+    return false;
+  }
+  if (!driver_tool_->IsFirmwareModeChangeNeeded(
+          convertIfaceTypeToFirmwareMode(type))) {
+    LOG(ERROR) << "Failed to change firmware mode";
+    return false;
+  }
+  return true;
+}
+
+bool WifiModeController::deinitialize() {
+  if (!driver_tool_->UnloadDriver()) {
+    LOG(ERROR) << "Failed to unload WiFi driver";
+    return false;
+  }
+  return true;
+}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.0/default/wifi_mode_controller.h b/wifi/1.0/default/wifi_mode_controller.h
new file mode 100644
index 0000000..a4147a9
--- /dev/null
+++ b/wifi/1.0/default/wifi_mode_controller.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_0 {
+namespace implementation {
+namespace mode_controller {
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+ public:
+  WifiModeController();
+
+  // Checks if a firmware mode change is necessary to support the specified
+  // iface type operations.
+  bool isFirmwareModeChangeNeeded(IfaceType type);
+  // Change the firmware mode to support the specified iface type operations.
+  bool changeFirmwareMode(IfaceType type);
+  // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+  // invoked.
+  bool deinitialize();
+
+ private:
+  std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.0/default/wifi_nan_iface.cpp b/wifi/1.0/default/wifi_nan_iface.cpp
index 48e75a5..a897520 100644
--- a/wifi/1.0/default/wifi_nan_iface.cpp
+++ b/wifi/1.0/default/wifi_nan_iface.cpp
@@ -17,6 +17,7 @@
 #include <android-base/logging.h>
 
 #include "hidl_return_util.h"
+#include "hidl_struct_util.h"
 #include "wifi_nan_iface.h"
 #include "wifi_status_util.h"
 
@@ -30,7 +31,47 @@
 WifiNanIface::WifiNanIface(
     const std::string& ifname,
     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {
+  // Register all the callbacks here. these should be valid for the lifetime
+  // of the object. Whenever the mode changes legacy HAL will remove
+  // all of these callbacks.
+  legacy_hal::NanCallbackHandlers callback_handlers;
+
+  // Callback for response.
+  callback_handlers.on_notify_response = [&](
+      legacy_hal::transaction_id id, const legacy_hal::NanResponseMsg& msg) {
+    NanResponseMsgHeader hidl_header;
+    if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(msg,
+                                                                &hidl_header)) {
+      LOG(ERROR) << "Failed to convert nan response header";
+      return;
+    }
+    // TODO: This is a union in the legacy HAL. Need to convert to appropriate
+    // callback based on type.
+    // Assuming |NanPublishResponseMsg| type here.
+    NanPublishResponse hidl_body;
+    if (!hidl_struct_util::convertLegacyNanPublishResponseToHidl(
+            msg.body.publish_response, &hidl_body)) {
+      LOG(ERROR) << "Failed to convert nan publish response";
+      return;
+    }
+    NanPublishResponseMsg hidl_msg;
+    hidl_msg.header = hidl_header;
+    hidl_msg.body = hidl_body;
+    for (const auto& callback : event_callbacks_) {
+      if (!callback->notifyPublishResponse(id, hidl_msg).getStatus().isOk()) {
+        LOG(ERROR) << "Failed to invoke the callback";
+      }
+    }
+  };
+  // TODO: Register the remaining callbacks.
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanRegisterCallbackHandlers(callback_handlers);
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+    invalidate();
+  }
+}
 
 void WifiNanIface::invalidate() {
   legacy_hal_.reset();
@@ -258,33 +299,60 @@
   return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
-WifiStatus WifiNanIface::enableRequestInternal(
-    uint32_t /* cmd_id */, const NanEnableRequest& /* msg */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiNanIface::enableRequestInternal(uint32_t cmd_id,
+                                               const NanEnableRequest& msg) {
+  legacy_hal::NanEnableRequest legacy_msg;
+  if (!hidl_struct_util::convertHidlNanEnableRequestToLegacy(msg,
+                                                             &legacy_msg)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanEnableRequest(cmd_id, legacy_msg);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiNanIface::disableRequestInternal(uint32_t /* cmd_id */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiNanIface::disableRequestInternal(uint32_t cmd_id) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanDisableRequest(cmd_id);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiNanIface::publishRequestInternal(
-    uint32_t /* cmd_id */, const NanPublishRequest& /* msg */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiNanIface::publishRequestInternal(uint32_t cmd_id,
+                                                const NanPublishRequest& msg) {
+  legacy_hal::NanPublishRequest legacy_msg;
+  if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
+                                                              &legacy_msg)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanPublishRequest(cmd_id, legacy_msg);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiNanIface::publishCancelRequestInternal(
-    uint32_t /* cmd_id */, const NanPublishCancelRequest& /* msg */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id, const NanPublishCancelRequest& msg) {
+  legacy_hal::NanPublishCancelRequest legacy_msg;
+  if (!hidl_struct_util::convertHidlNanPublishCancelRequestToLegacy(
+          msg, &legacy_msg)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanPublishCancelRequest(cmd_id, legacy_msg);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
+
 WifiStatus WifiNanIface::subscribeRequestInternal(
-    uint32_t /* cmd_id */, const NanSubscribeRequest& /* msg */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id, const NanSubscribeRequest& msg) {
+  legacy_hal::NanSubscribeRequest legacy_msg;
+  if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(msg,
+                                                                &legacy_msg)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->nanSubscribeRequest(cmd_id, legacy_msg);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
+
 WifiStatus WifiNanIface::subscribeCancelRequestInternal(
     uint32_t /* cmd_id */, const NanSubscribeCancelRequest& /* msg */) {
   // TODO implement
diff --git a/wifi/1.0/default/wifi_rtt_controller.cpp b/wifi/1.0/default/wifi_rtt_controller.cpp
index 6ac0629..f18feae 100644
--- a/wifi/1.0/default/wifi_rtt_controller.cpp
+++ b/wifi/1.0/default/wifi_rtt_controller.cpp
@@ -17,6 +17,7 @@
 #include <android-base/logging.h>
 
 #include "hidl_return_util.h"
+#include "hidl_struct_util.h"
 #include "wifi_rtt_controller.h"
 #include "wifi_status_util.h"
 
@@ -42,6 +43,11 @@
   return is_valid_;
 }
 
+std::vector<sp<IWifiRttControllerEventCallback>>
+WifiRttController::getEventCallbacks() {
+  return event_callbacks_;
+}
+
 Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
   return validateAndCall(this,
                          WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -83,28 +89,6 @@
                          addrs);
 }
 
-Return<void> WifiRttController::setChannelMap(uint32_t cmd_id,
-                                              const RttChannelMap& params,
-                                              uint32_t num_dw,
-                                              setChannelMap_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::setChannelMapInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         params,
-                         num_dw);
-}
-
-Return<void> WifiRttController::clearChannelMap(
-    uint32_t cmd_id, clearChannelMap_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::clearChannelMapInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
 Return<void> WifiRttController::getCapabilities(
     getCapabilities_cb hidl_status_cb) {
   return validateAndCall(this,
@@ -113,22 +97,6 @@
                          hidl_status_cb);
 }
 
-Return<void> WifiRttController::setDebugCfg(RttDebugType type,
-                                            setDebugCfg_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::setDebugCfgInternal,
-                         hidl_status_cb,
-                         type);
-}
-
-Return<void> WifiRttController::getDebugInfo(getDebugInfo_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::getDebugInfoInternal,
-                         hidl_status_cb);
-}
-
 Return<void> WifiRttController::setLci(uint32_t cmd_id,
                                        const RttLciInformation& lci,
                                        setLci_cb hidl_status_cb) {
@@ -162,7 +130,7 @@
 Return<void> WifiRttController::enableResponder(
     uint32_t cmd_id,
     const WifiChannelInfo& channel_hint,
-    uint32_t maxDurationSeconds,
+    uint32_t max_duration_seconds,
     const RttResponder& info,
     enableResponder_cb hidl_status_cb) {
   return validateAndCall(this,
@@ -171,7 +139,7 @@
                          hidl_status_cb,
                          cmd_id,
                          channel_hint,
-                         maxDurationSeconds,
+                         max_duration_seconds,
                          info);
 }
 
@@ -197,77 +165,130 @@
 }
 
 WifiStatus WifiRttController::rangeRequestInternal(
-    uint32_t /* cmd_id */, const std::vector<RttConfig>& /* rtt_configs */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+  std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+  if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
+          rtt_configs, &legacy_configs)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  android::wp<WifiRttController> weak_ptr_this(this);
+  const auto& on_results_callback = [weak_ptr_this](
+      legacy_hal::wifi_request_id id,
+      const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+    const auto shared_ptr_this = weak_ptr_this.promote();
+    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+      LOG(ERROR) << "Callback invoked on an invalid object";
+      return;
+    }
+    std::vector<RttResult> hidl_results;
+    if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
+            results, &hidl_results)) {
+      LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+      return;
+    }
+    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+      callback->onResults(id, hidl_results);
+    }
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startRttRangeRequest(
+          cmd_id, legacy_configs, on_results_callback);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiRttController::rangeCancelInternal(
-    uint32_t /* cmd_id */,
-    const std::vector<hidl_array<uint8_t, 6>>& /* addrs */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::setChannelMapInternal(
-    uint32_t /* cmd_id */,
-    const RttChannelMap& /* params */,
-    uint32_t /* num_dw */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::clearChannelMapInternal(uint32_t /* cmd_id */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+  std::vector<std::array<uint8_t, 6>> legacy_addrs;
+  for (const auto& addr : addrs) {
+    legacy_addrs.push_back(addr);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->cancelRttRangeRequest(cmd_id, legacy_addrs);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 std::pair<WifiStatus, RttCapabilities>
 WifiRttController::getCapabilitiesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::wifi_rtt_capabilities legacy_caps;
+  std::tie(legacy_status, legacy_caps) =
+      legacy_hal_.lock()->getRttCapabilities();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  RttCapabilities hidl_caps;
+  if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
+                                                            &hidl_caps)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
-WifiStatus WifiRttController::setDebugCfgInternal(RttDebugType /* type */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
+                                             const RttLciInformation& lci) {
+  legacy_hal::wifi_lci_information legacy_lci;
+  if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
+                                                              &legacy_lci)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->setRttLci(cmd_id, legacy_lci);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, RttDebugInfo> WifiRttController::getDebugInfoInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-}
-
-WifiStatus WifiRttController::setLciInternal(
-    uint32_t /* cmd_id */, const RttLciInformation& /* lci */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::setLcrInternal(
-    uint32_t /* cmd_id */, const RttLcrInformation& /* lcr */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
+                                             const RttLcrInformation& lcr) {
+  legacy_hal::wifi_lcr_information legacy_lcr;
+  if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
+                                                              &legacy_lcr)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->setRttLcr(cmd_id, legacy_lcr);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 std::pair<WifiStatus, RttResponder>
 WifiRttController::getResponderInfoInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::wifi_rtt_responder legacy_responder;
+  std::tie(legacy_status, legacy_responder) =
+      legacy_hal_.lock()->getRttResponderInfo();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  RttResponder hidl_responder;
+  if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
+                                                         &hidl_responder)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
 }
 
 WifiStatus WifiRttController::enableResponderInternal(
-    uint32_t /* cmd_id */,
-    const WifiChannelInfo& /* channel_hint */,
-    uint32_t /* maxDurationSeconds */,
-    const RttResponder& /* info */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id,
+    const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds,
+    const RttResponder& info) {
+  legacy_hal::wifi_channel_info legacy_channel_info;
+  if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
+          channel_hint, &legacy_channel_info)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_rtt_responder legacy_responder;
+  if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
+                                                         &legacy_responder)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
+      cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiRttController::disableResponderInternal(uint32_t /* cmd_id */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->disableRttResponder(cmd_id);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/wifi/1.0/default/wifi_rtt_controller.h b/wifi/1.0/default/wifi_rtt_controller.h
index 3dd5340..7c0abca 100644
--- a/wifi/1.0/default/wifi_rtt_controller.h
+++ b/wifi/1.0/default/wifi_rtt_controller.h
@@ -40,6 +40,7 @@
   // Refer to |WifiChip::invalidate()|.
   void invalidate();
   bool isValid();
+  std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
 
   // HIDL methods exposed.
   Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
@@ -52,16 +53,7 @@
   Return<void> rangeCancel(uint32_t cmd_id,
                            const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
                            rangeCancel_cb hidl_status_cb) override;
-  Return<void> setChannelMap(uint32_t cmd_id,
-                             const RttChannelMap& params,
-                             uint32_t num_dw,
-                             setChannelMap_cb hidl_status_cb) override;
-  Return<void> clearChannelMap(uint32_t cmd_id,
-                               clearChannelMap_cb hidl_status_cb) override;
   Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-  Return<void> setDebugCfg(RttDebugType type,
-                           setDebugCfg_cb hidl_status_cb) override;
-  Return<void> getDebugInfo(getDebugInfo_cb hidl_status_cb) override;
   Return<void> setLci(uint32_t cmd_id,
                       const RttLciInformation& lci,
                       setLci_cb hidl_status_cb) override;
@@ -71,7 +63,7 @@
   Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
   Return<void> enableResponder(uint32_t cmd_id,
                                const WifiChannelInfo& channel_hint,
-                               uint32_t maxDurationSeconds,
+                               uint32_t max_duration_seconds,
                                const RttResponder& info,
                                enableResponder_cb hidl_status_cb) override;
   Return<void> disableResponder(uint32_t cmd_id,
@@ -86,19 +78,13 @@
                                   const std::vector<RttConfig>& rtt_configs);
   WifiStatus rangeCancelInternal(
       uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
-  WifiStatus setChannelMapInternal(uint32_t cmd_id,
-                                   const RttChannelMap& params,
-                                   uint32_t num_dw);
-  WifiStatus clearChannelMapInternal(uint32_t cmd_id);
   std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal();
-  WifiStatus setDebugCfgInternal(RttDebugType type);
-  std::pair<WifiStatus, RttDebugInfo> getDebugInfoInternal();
   WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
   WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
   std::pair<WifiStatus, RttResponder> getResponderInfoInternal();
   WifiStatus enableResponderInternal(uint32_t cmd_id,
                                      const WifiChannelInfo& channel_hint,
-                                     uint32_t maxDurationSeconds,
+                                     uint32_t max_duration_seconds,
                                      const RttResponder& info);
   WifiStatus disableResponderInternal(uint32_t cmd_id);
 
diff --git a/wifi/1.0/default/wifi_sta_iface.cpp b/wifi/1.0/default/wifi_sta_iface.cpp
index 6365032..c91a99b 100644
--- a/wifi/1.0/default/wifi_sta_iface.cpp
+++ b/wifi/1.0/default/wifi_sta_iface.cpp
@@ -17,6 +17,7 @@
 #include <android-base/logging.h>
 
 #include "hidl_return_util.h"
+#include "hidl_struct_util.h"
 #include "wifi_sta_iface.h"
 #include "wifi_status_util.h"
 
@@ -42,6 +43,10 @@
   return is_valid_;
 }
 
+std::vector<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+  return event_callbacks_;
+}
+
 Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
   return validateAndCall(this,
                          WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -158,6 +163,29 @@
                          hidl_status_cb);
 }
 
+Return<void> WifiStaIface::startRssiMonitoring(
+    uint32_t cmd_id,
+    int32_t max_rssi,
+    int32_t min_rssi,
+    startRssiMonitoring_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                         &WifiStaIface::startRssiMonitoringInternal,
+                         hidl_status_cb,
+                         cmd_id,
+                         max_rssi,
+                         min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(
+    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                         &WifiStaIface::stopRssiMonitoringInternal,
+                         hidl_status_cb,
+                         cmd_id);
+}
+
 Return<void> WifiStaIface::startDebugPacketFateMonitoring(
     startDebugPacketFateMonitoring_cb hidl_status_cb) {
   return validateAndCall(this,
@@ -206,83 +234,249 @@
 }
 
 std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), 0};
+  legacy_hal::wifi_error legacy_status;
+  uint32_t legacy_feature_set;
+  std::tie(legacy_status, legacy_feature_set) =
+      legacy_hal_.lock()->getSupportedFeatureSet();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), 0};
+  }
+  uint32_t legacy_logger_feature_set;
+  std::tie(legacy_status, legacy_logger_feature_set) =
+      legacy_hal_.lock()->getLoggerSupportedFeatureSet();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), 0};
+  }
+  uint32_t hidl_caps;
+  if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+          legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
 std::pair<WifiStatus, StaApfPacketFilterCapabilities>
 WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::PacketFilterCapabilities legacy_caps;
+  std::tie(legacy_status, legacy_caps) =
+      legacy_hal_.lock()->getPacketFilterCapabilities();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  StaApfPacketFilterCapabilities hidl_caps;
+  if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
+                                                            &hidl_caps)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
 WifiStatus WifiStaIface::installApfPacketFilterInternal(
-    uint32_t /* cmd_id */, const std::vector<uint8_t>& /* program */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->setPacketFilter(program);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 std::pair<WifiStatus, StaBackgroundScanCapabilities>
 WifiStaIface::getBackgroundScanCapabilitiesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::wifi_gscan_capabilities legacy_caps;
+  std::tie(legacy_status, legacy_caps) =
+      legacy_hal_.lock()->getGscanCapabilities();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  StaBackgroundScanCapabilities hidl_caps;
+  if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
+                                                              &hidl_caps)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
 std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
 WifiStaIface::getValidFrequenciesForBackgroundScanInternal(
-    StaBackgroundScanBand /* band */) {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    StaBackgroundScanBand band) {
+  static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
+  legacy_hal::wifi_error legacy_status;
+  std::vector<uint32_t> valid_frequencies;
+  std::tie(legacy_status, valid_frequencies) =
+      legacy_hal_.lock()->getValidFrequenciesForGscan(
+          hidl_struct_util::convertHidlGscanBandToLegacy(band));
+  return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
 }
 
 WifiStatus WifiStaIface::startBackgroundScanInternal(
-    uint32_t /* cmd_id */, const StaBackgroundScanParameters& /* params */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
+  legacy_hal::wifi_scan_cmd_params legacy_params;
+  if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
+                                                        &legacy_params)) {
+    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+  }
+  android::wp<WifiStaIface> weak_ptr_this(this);
+  const auto& on_failure_callback =
+      [weak_ptr_this](legacy_hal::wifi_request_id id) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+          LOG(ERROR) << "Callback invoked on an invalid object";
+          return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+          callback->onBackgroundScanFailure(id);
+        }
+      };
+  const auto& on_results_callback = [weak_ptr_this](
+      legacy_hal::wifi_request_id id,
+      const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+    const auto shared_ptr_this = weak_ptr_this.promote();
+    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+      LOG(ERROR) << "Callback invoked on an invalid object";
+      return;
+    }
+    std::vector<StaScanData> hidl_scan_datas;
+    if (!hidl_struct_util::convertLegacyVectorOfCachedGscanResultsToHidl(
+            results, &hidl_scan_datas)) {
+      LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+      return;
+    }
+    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+      callback->onBackgroundScanResults(id, hidl_scan_datas);
+    }
+  };
+  const auto& on_full_result_callback = [weak_ptr_this](
+      legacy_hal::wifi_request_id id,
+      const legacy_hal::wifi_scan_result* result,
+      uint32_t /* buckets_scanned */) {
+    const auto shared_ptr_this = weak_ptr_this.promote();
+    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+      LOG(ERROR) << "Callback invoked on an invalid object";
+      return;
+    }
+    StaScanResult hidl_scan_result;
+    if (!hidl_struct_util::convertLegacyGscanResultToHidl(
+            *result, true, &hidl_scan_result)) {
+      LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+      return;
+    }
+    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+      callback->onBackgroundFullScanResult(id, hidl_scan_result);
+    }
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startGscan(cmd_id,
+                                     legacy_params,
+                                     on_failure_callback,
+                                     on_results_callback,
+                                     on_full_result_callback);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t /* cmd_id */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(cmd_id);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(
-    bool /* debug */) {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->enableLinkLayerStats(debug);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->disableLinkLayerStats();
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 std::pair<WifiStatus, StaLinkLayerStats>
 WifiStaIface::getLinkLayerStatsInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  legacy_hal::LinkLayerStats legacy_stats;
+  std::tie(legacy_status, legacy_stats) =
+      legacy_hal_.lock()->getLinkLayerStats();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  StaLinkLayerStats hidl_stats;
+  if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+                                                           &hidl_stats)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
+                                                     int32_t max_rssi,
+                                                     int32_t min_rssi) {
+  android::wp<WifiStaIface> weak_ptr_this(this);
+  const auto& on_threshold_breached_callback = [weak_ptr_this](
+      legacy_hal::wifi_request_id id,
+      std::array<uint8_t, 6> bssid,
+      int8_t rssi) {
+    const auto shared_ptr_this = weak_ptr_this.promote();
+    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+      LOG(ERROR) << "Callback invoked on an invalid object";
+      return;
+    }
+    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+      callback->onRssiThresholdBreached(id, bssid, rssi);
+    }
+  };
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startRssiMonitoring(
+          cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
+  return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->stopRssiMonitoring(cmd_id);
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  legacy_hal::wifi_error legacy_status =
+      legacy_hal_.lock()->startPktFateMonitoring();
+  return createWifiStatusFromLegacyError(legacy_status);
 }
 
 WifiStatus WifiStaIface::stopDebugPacketFateMonitoringInternal() {
-  // TODO implement
-  return createWifiStatus(WifiStatusCode::SUCCESS);
+  // There is no stop in legacy HAL implementation.
+  return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
 WifiStaIface::getDebugTxPacketFatesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+  std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+  if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
+          legacy_fates, &hidl_fates)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
 }
 
 std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
 WifiStaIface::getDebugRxPacketFatesInternal() {
-  // TODO implement
-  return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+  legacy_hal::wifi_error legacy_status;
+  std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+  std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates();
+  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+    return {createWifiStatusFromLegacyError(legacy_status), {}};
+  }
+  std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+  if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
+          legacy_fates, &hidl_fates)) {
+    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+  }
+  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
 }
 
 }  // namespace implementation
diff --git a/wifi/1.0/default/wifi_sta_iface.h b/wifi/1.0/default/wifi_sta_iface.h
index 09a883c..b4f2721 100644
--- a/wifi/1.0/default/wifi_sta_iface.h
+++ b/wifi/1.0/default/wifi_sta_iface.h
@@ -39,6 +39,7 @@
   // Refer to |WifiChip::invalidate()|.
   void invalidate();
   bool isValid();
+  std::vector<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
 
   // HIDL methods exposed.
   Return<void> getName(getName_cb hidl_status_cb) override;
@@ -69,6 +70,13 @@
   Return<void> disableLinkLayerStatsCollection(
       disableLinkLayerStatsCollection_cb hidl_status_cb) override;
   Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
+  Return<void> startRssiMonitoring(
+      uint32_t cmd_id,
+      int32_t max_rssi,
+      int32_t min_rssi,
+      startRssiMonitoring_cb hidl_status_cb) override;
+  Return<void> stopRssiMonitoring(
+      uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
   Return<void> startDebugPacketFateMonitoring(
       startDebugPacketFateMonitoring_cb hidl_status_cb) override;
   Return<void> stopDebugPacketFateMonitoring(
@@ -99,6 +107,10 @@
   WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
   WifiStatus disableLinkLayerStatsCollectionInternal();
   std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
+  WifiStatus startRssiMonitoringInternal(uint32_t cmd_id,
+                                         int32_t max_rssi,
+                                         int32_t min_rssi);
+  WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
   WifiStatus startDebugPacketFateMonitoringInternal();
   WifiStatus stopDebugPacketFateMonitoringInternal();
   std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index 9e53377..8dd33b5 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -491,7 +491,7 @@
    * Indicates that a scan was interrupted/did not occur so results may be
    * incomplete.
    */
-  WIFI_SCAN_FLAG_INTERRUPTED = 1 << 0,
+  INTERRUPTED = 1 << 0,
 };
 
 /**
@@ -2183,13 +2183,6 @@
 };
 
 /**
- * NBD ranging channel map.
- */
-struct RttChannelMap {
-  WifiChannelInMhz[32] availablity;
-};
-
-/**
  * RTT Capabilities.
  */
 struct RttCapabilities {
@@ -2231,45 +2224,6 @@
 };
 
 /**
- * Debugging definitions.
- */
-enum RttDebugType : uint32_t {
-  DISABLE,
-  LOG,
-  PROTO,
-  BURST,
-  ACCURACY,
-  LOGDETAIL,
-};
-
-enum RttDebugFormat : uint32_t {
-  TXT,
-  BINARY,
-};
-
-/**
- * Debug info.
- */
-struct RttDebugInfo {
-  /**
-   * Version info.
-   */
-  uint32_t version;
-  /**
-   * Debug data type.
-   */
-  RttDebugType type;
-  /**
-   * Debug data format.
-   */
-  RttDebugFormat format;
-  /**
-   * Debug data content.
-   */
-  vec<uint8_t> data;
-};
-
-/**
  * Structs for setting LCI/LCR information to be provided to a requestor.
  */
 enum RttMotionPattern : uint32_t {
@@ -3053,7 +3007,7 @@
  */
 struct WifiDebugTxPacketFateReport {
   WifiDebugTxPacketFate fate;
-  WifiDebugPacketFateFrameInfo frameInf;
+  WifiDebugPacketFateFrameInfo frameInfo;
 };
 
 /**