DO NOT MERGE - Merge Android 10 into master

Bug: 139893257
Change-Id: Ic9046fa1839a2aed313702f73f1c809d7879490b
diff --git a/Android.bp b/Android.bp
index 33c8816..d4a928e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -41,7 +41,6 @@
         "libhidltransport",
         "libminijail",
         "libutils",
-        "libwifi-system",
         "libwifi-system-iface",
     ],
     static_libs: ["libwificond"],
@@ -83,7 +82,6 @@
         "libutils",
         "libhidlbase",
         "libhidltransport",
-        "libwifi-system",
         "libwifi-system-iface",
     ],
     whole_static_libs: [
@@ -158,6 +156,7 @@
         "aidl/android/net/wifi/IInterfaceEventCallback.aidl",
         "aidl/android/net/wifi/IPnoScanEvent.aidl",
         "aidl/android/net/wifi/IScanEvent.aidl",
+        "aidl/android/net/wifi/ISendMgmtFrameEvent.aidl",
         "aidl/android/net/wifi/IWificond.aidl",
         "aidl/android/net/wifi/IWifiScannerImpl.aidl",
     ],
@@ -224,7 +223,6 @@
     static_libs: [
         "libgmock",
         "libgtest",
-        "libwifi-system-test",
         "libwifi-system-iface-test",
         "libwificond",
         "libwificond_nl",
@@ -238,7 +236,6 @@
         "libhidlbase",
         "liblog",
         "libutils",
-        "libwifi-system",
         "libwifi-system-iface",
     ],
 }
@@ -254,7 +251,6 @@
         "tests/integration/client_interface_test.cpp",
         "tests/integration/life_cycle_test.cpp",
         "tests/integration/scanner_test.cpp",
-        "tests/integration/service_test.cpp",
         "tests/main.cpp",
         "tests/shell_unittest.cpp",
     ],
@@ -263,7 +259,6 @@
         "libbinder",
         "libcutils",
         "libutils",
-        "libwifi-system",
         "libwifi-system-iface",
     ],
     static_libs: [
diff --git a/aidl/android/net/wifi/IApInterface.aidl b/aidl/android/net/wifi/IApInterface.aidl
index 2d7d6da..b37c068 100644
--- a/aidl/android/net/wifi/IApInterface.aidl
+++ b/aidl/android/net/wifi/IApInterface.aidl
@@ -26,15 +26,11 @@
   const int ENCRYPTION_TYPE_WPA = 1;
   const int ENCRYPTION_TYPE_WPA2 = 2;
 
-  // Start up an instance of hostapd associated with this interface.
+  // Register a callback object for this interface.
   //
   // @param callback Object to add a set of event callbacks.
   // @return true on success.
-  boolean startHostapd(IApInterfaceEventCallback callback);
-
-  // Stop a previously started instance of hostapd.
-  // @return true on success.
-  boolean stopHostapd();
+  boolean registerCallback(IApInterfaceEventCallback callback);
 
   // Retrieve the name of the network interface corresponding to this
   // IApInterface instance (e.g. "wlan0")
diff --git a/aidl/android/net/wifi/IClientInterface.aidl b/aidl/android/net/wifi/IClientInterface.aidl
index ed34886..1b8b404 100644
--- a/aidl/android/net/wifi/IClientInterface.aidl
+++ b/aidl/android/net/wifi/IClientInterface.aidl
@@ -16,6 +16,7 @@
 
 package android.net.wifi;
 
+import android.net.wifi.ISendMgmtFrameEvent;
 import android.net.wifi.IWifiScannerImpl;
 
 // IClientInterface represents a network interface that can be used to connect
@@ -32,6 +33,7 @@
   // First element in array is the RSSI value in dBM.
   // Second element in array is the transmission bit rate in Mbps.
   // Third element in array is the association frequency in MHz.
+  // Fourth element in array is the last received packet bit rate in Mbps.
   // This call is valid only when interface is associated with an AP, otherwise
   // it returns an empty array.
   int[] signalPoll();
@@ -51,4 +53,17 @@
   // Set the MAC address of this interface
   // Returns true if the set was successful
   boolean setMacAddress(in byte[] mac);
+
+  // Sends an arbitrary 802.11 management frame on the current channel.
+  // @param frame Bytes of the 802.11 management frame to be sent, including the
+  //     header, but not including the frame check sequence (FCS).
+  // @param Callback triggered when the transmitted frame is ACKed or the
+  //     transmission fails.
+  // @param mcs MCS rate which the management frame will be sent at. If mcs < 0,
+  //     the driver will select the rate automatically. If the device does not
+  //     support sending the frame at a specified MCS rate, the transmission
+  //     will be aborted and ISendMgmtFrameEvent.OnFailure() will be called with
+  //     reason ISendMgmtFrameEvent.SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED.
+  oneway void SendMgmtFrame(
+      in byte[] frame, in ISendMgmtFrameEvent callback, int mcs);
 }
diff --git a/aidl/android/net/wifi/ISendMgmtFrameEvent.aidl b/aidl/android/net/wifi/ISendMgmtFrameEvent.aidl
new file mode 100644
index 0000000..3af84aa
--- /dev/null
+++ b/aidl/android/net/wifi/ISendMgmtFrameEvent.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+// A callback to notify the results of sending a management frame.
+interface ISendMgmtFrameEvent {
+  // Error codes for OnFailure():
+
+  // Unknown error.
+  const int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
+
+  // Specifying the MCS rate is not supported by this device.
+  const int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
+
+  // Driver reported that no ACK was received for the transmitted frame.
+  const int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
+
+  // Timed out while waiting for a response from the driver about the status
+  // of the transmitted frame.
+  const int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
+
+  // An existing transmission is in progress. Another frame cannot be sent until
+  // the first transmission completes.
+  const int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
+
+  // Called when the management frame was successfully sent and ACKed by the
+  // recipient.
+  // @param elapsedTimeMs The elapsed time between when the management frame was
+  //     sent and when the ACK was processed, in milliseconds, as measured by
+  //     wificond. This includes the time that the send frame spent queuing
+  //     before it was sent, any firmware retries, and the time the received
+  //     ACK spent queuing before it was processed.
+  oneway void OnAck(int elapsedTimeMs);
+
+  // Called when the send failed.
+  // @param reason The error code for the failure.
+  oneway void OnFailure(int reason);
+}
diff --git a/aidl/android/net/wifi/IWificond.aidl b/aidl/android/net/wifi/IWificond.aidl
index 6a6920b..d3a3089 100644
--- a/aidl/android/net/wifi/IWificond.aidl
+++ b/aidl/android/net/wifi/IWificond.aidl
@@ -59,16 +59,6 @@
     // Returrns null on failure.
     @nullable int[] getAvailableDFSChannels();
 
-    // Enable wpa_supplicant.
-    // Returns true if supplicant was successfully enabled,
-    // or is already enabled.
-    boolean enableSupplicant();
-
-    // Disable wpa_supplicant.
-    // Returns true if supplicant was successfully disabled,
-    // or is already disabled.
-    boolean disableSupplicant();
-
     // Register a callback to receive interface status updates.
     //
     // Multiple callbacks can be registered simultaneously.
diff --git a/ap_interface_binder.cpp b/ap_interface_binder.cpp
index 4d6a321..56e779f 100644
--- a/ap_interface_binder.cpp
+++ b/ap_interface_binder.cpp
@@ -17,7 +17,6 @@
 #include "wificond/ap_interface_binder.h"
 
 #include <android-base/logging.h>
-#include <wifi_system/hostapd_manager.h>
 
 #include "wificond/ap_interface_impl.h"
 
@@ -73,48 +72,20 @@
   ap_interface_event_callback_->onSoftApChannelSwitched(frequency, bandwidth);
 }
 
-binder::Status ApInterfaceBinder::startHostapd(
+binder::Status ApInterfaceBinder::registerCallback(
     const sp<IApInterfaceEventCallback>& callback, bool* out_success) {
-  *out_success = false;
-  if (!impl_) {
-    LOG(WARNING) << "Cannot start hostapd on dead ApInterface.";
-    return binder::Status::ok();
-  }
-  *out_success = impl_->StartHostapd();
-  if (*out_success) {
-    ap_interface_event_callback_ = callback;
-  }
-  return binder::Status::ok();
-}
-
-binder::Status ApInterfaceBinder::stopHostapd(bool* out_success) {
-  *out_success = false;
-  if (!impl_) {
-    LOG(WARNING) << "Cannot stop hostapd on dead ApInterface.";
-    return binder::Status::ok();
-  }
-  *out_success = impl_->StopHostapd();
-  ap_interface_event_callback_.clear();
+  *out_success = true;
+  ap_interface_event_callback_ = callback;
   return binder::Status::ok();
 }
 
 binder::Status ApInterfaceBinder::getInterfaceName(std::string* out_name) {
-  if (!impl_) {
-    LOG(WARNING) << "Cannot get interface name from dead ApInterface";
-    return binder::Status::ok();
-  }
   *out_name = impl_->GetInterfaceName();
   return binder::Status::ok();
 }
 
 binder::Status ApInterfaceBinder::getNumberOfAssociatedStations(
     int* out_num_of_stations) {
-  if (!impl_) {
-    LOG(WARNING) << "Cannot get number of associated stations "
-                 << "from dead ApInterface";
-    *out_num_of_stations = -1;
-    return binder::Status::ok();
-  }
   *out_num_of_stations = impl_->GetNumberOfAssociatedStations();
   return binder::Status::ok();
 }
diff --git a/ap_interface_binder.h b/ap_interface_binder.h
index ea1c9d5..7e332f5 100644
--- a/ap_interface_binder.h
+++ b/ap_interface_binder.h
@@ -46,10 +46,9 @@
   void NotifySoftApChannelSwitched(int frequency,
                                    ChannelBandwidth channel_bandwidth);
 
-  binder::Status startHostapd(
+  binder::Status registerCallback(
       const sp<net::wifi::IApInterfaceEventCallback>& callback,
       bool* out_success) override;
-  binder::Status stopHostapd(bool* out_success) override;
   binder::Status getInterfaceName(std::string* out_name) override;
   binder::Status getNumberOfAssociatedStations(
       int* out_num_of_stations) override;
diff --git a/ap_interface_impl.cpp b/ap_interface_impl.cpp
index 28cd4f9..f39e9c1 100644
--- a/ap_interface_impl.cpp
+++ b/ap_interface_impl.cpp
@@ -24,12 +24,11 @@
 #include "wificond/logging_utils.h"
 
 using android::net::wifi::IApInterface;
-using android::wifi_system::HostapdManager;
 using android::wifi_system::InterfaceTool;
+using std::array;
 using std::endl;
 using std::string;
 using std::unique_ptr;
-using std::vector;
 
 using namespace std::placeholders;
 
@@ -39,13 +38,11 @@
 ApInterfaceImpl::ApInterfaceImpl(const string& interface_name,
                                  uint32_t interface_index,
                                  NetlinkUtils* netlink_utils,
-                                 InterfaceTool* if_tool,
-                                 HostapdManager* hostapd_manager)
+                                 InterfaceTool* if_tool)
     : interface_name_(interface_name),
       interface_index_(interface_index),
       netlink_utils_(netlink_utils),
       if_tool_(if_tool),
-      hostapd_manager_(hostapd_manager),
       binder_(new ApInterfaceBinder(this)),
       number_of_associated_stations_(0) {
   // This log keeps compiler happy.
@@ -83,38 +80,9 @@
   *ss << "------- Dump End -------" << endl;
 }
 
-bool ApInterfaceImpl::StartHostapd() {
-  return hostapd_manager_->StartHostapd();
-}
-
-bool ApInterfaceImpl::StopHostapd() {
-  // Drop SIGKILL on hostapd.
-  if (!hostapd_manager_->StopHostapd()) {
-    // Logging was done internally.
-    return false;
-  }
-
-  // Take down the interface.
-  if (!if_tool_->SetUpState(interface_name_.c_str(), false)) {
-    // Logging was done internally.
-    return false;
-  }
-
-  // Since wificond SIGKILLs hostapd, hostapd has no chance to handle
-  // the cleanup.
-  // Besides taking down the interface, we also need to set the interface mode
-  // back to station mode for the cleanup.
-  if (!netlink_utils_->SetInterfaceMode(interface_index_,
-                                        NetlinkUtils::STATION_MODE)) {
-    LOG(ERROR) << "Failed to set interface back to station mode";
-    return false;
-  }
-
-  return true;
-}
-
-void ApInterfaceImpl::OnStationEvent(StationEvent event,
-                                     const vector<uint8_t>& mac_address) {
+void ApInterfaceImpl::OnStationEvent(
+    StationEvent event,
+    const array<uint8_t, ETH_ALEN>& mac_address) {
   if (event == NEW_STATION) {
     LOG(INFO) << "New station "
               << LoggingUtils::GetMacString(mac_address)
diff --git a/ap_interface_impl.h b/ap_interface_impl.h
index 3bbbcef..ab3bac3 100644
--- a/ap_interface_impl.h
+++ b/ap_interface_impl.h
@@ -17,11 +17,12 @@
 #ifndef WIFICOND_AP_INTERFACE_IMPL_H_
 #define WIFICOND_AP_INTERFACE_IMPL_H_
 
+#include <array>
 #include <string>
-#include <vector>
+
+#include <linux/if_ether.h>
 
 #include <android-base/macros.h>
-#include <wifi_system/hostapd_manager.h>
 #include <wifi_system/interface_tool.h>
 
 #include "wificond/net/netlink_manager.h"
@@ -43,15 +44,12 @@
   ApInterfaceImpl(const std::string& interface_name,
                   uint32_t interface_index,
                   NetlinkUtils* netlink_utils,
-                  wifi_system::InterfaceTool* if_tool,
-                  wifi_system::HostapdManager* hostapd_manager);
+                  wifi_system::InterfaceTool* if_tool);
   ~ApInterfaceImpl();
 
   // Get a pointer to the binder representing this ApInterfaceImpl.
   android::sp<android::net::wifi::IApInterface> GetBinder() const;
 
-  bool StartHostapd();
-  bool StopHostapd();
   std::string GetInterfaceName() { return interface_name_; }
   int GetNumberOfAssociatedStations() const;
   void Dump(std::stringstream* ss) const;
@@ -61,14 +59,13 @@
   const uint32_t interface_index_;
   NetlinkUtils* const netlink_utils_;
   wifi_system::InterfaceTool* const if_tool_;
-  wifi_system::HostapdManager* const hostapd_manager_;
   const android::sp<ApInterfaceBinder> binder_;
 
   // Number of associated stations.
   int number_of_associated_stations_;
 
   void OnStationEvent(StationEvent event,
-                      const std::vector<uint8_t>& mac_address);
+                      const std::array<uint8_t, ETH_ALEN>& mac_address);
 
   void OnChannelSwitchEvent(uint32_t frequency, ChannelBandwidth bandwidth);
 
diff --git a/client_interface_binder.cpp b/client_interface_binder.cpp
index 5b60844..960be8b 100644
--- a/client_interface_binder.cpp
+++ b/client_interface_binder.cpp
@@ -16,13 +16,19 @@
 
 #include "wificond/client_interface_binder.h"
 
+#include <algorithm>
 #include <vector>
 
+#include <linux/if_ether.h>
+
+#include <android-base/logging.h>
+
 #include <binder/Status.h>
 
 #include "wificond/client_interface_impl.h"
 
 using android::binder::Status;
+using android::net::wifi::ISendMgmtFrameEvent;
 using android::net::wifi::IWifiScannerImpl;
 using std::vector;
 
@@ -58,7 +64,8 @@
   if (impl_ == nullptr) {
     return Status::ok();
   }
-  *out_mac_address = impl_->GetMacAddress();
+  const std::array<uint8_t, ETH_ALEN>& mac = impl_->GetMacAddress();
+  *out_mac_address = vector<uint8_t>(mac.begin(), mac.end());
   return Status::ok();
 }
 
@@ -82,7 +89,29 @@
 
 
 Status ClientInterfaceBinder::setMacAddress(const vector<uint8_t>& mac, bool* success) {
-  *success = impl_ && impl_->SetMacAddress(mac);
+  if (impl_ == nullptr) {
+    *success = false;
+    return Status::ok();
+  }
+  if (mac.size() != ETH_ALEN) {
+    LOG(ERROR) << "Invalid MAC length " << mac.size();
+    *success = false;
+    return Status::ok();
+  }
+  std::array<uint8_t, ETH_ALEN> mac_array;
+  std::copy_n(mac.begin(), ETH_ALEN, mac_array.begin());
+  *success = impl_->SetMacAddress(mac_array);
+  return Status::ok();
+}
+
+Status ClientInterfaceBinder::SendMgmtFrame(const vector<uint8_t>& frame,
+    const sp<ISendMgmtFrameEvent>& callback, int32_t mcs) {
+  if (impl_ == nullptr) {
+    callback->OnFailure(ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_UNKNOWN);
+    return Status::ok();
+  }
+  // TODO (b/112029045) validate mcs
+  impl_->SendMgmtFrame(frame, callback, mcs);
   return Status::ok();
 }
 
diff --git a/client_interface_binder.h b/client_interface_binder.h
index ecd5700..b1fceea 100644
--- a/client_interface_binder.h
+++ b/client_interface_binder.h
@@ -21,6 +21,7 @@
 #include <binder/Status.h>
 
 #include "android/net/wifi/BnClientInterface.h"
+#include "android/net/wifi/ISendMgmtFrameEvent.h"
 
 namespace android {
 namespace wificond {
@@ -48,6 +49,10 @@
       ::android::sp<::android::net::wifi::IWifiScannerImpl>* out_wifi_scanner_impl) override;
   ::android::binder::Status setMacAddress(
       const ::std::vector<uint8_t>& mac, bool* success) override;
+  ::android::binder::Status SendMgmtFrame(
+      const ::std::vector<uint8_t>& frame,
+      const sp<::android::net::wifi::ISendMgmtFrameEvent>& callback,
+      int32_t mcs) override;
  private:
   ClientInterfaceImpl* impl_;
 
diff --git a/client_interface_impl.cpp b/client_interface_impl.cpp
index 2ea6871..60bae8e 100644
--- a/client_interface_impl.cpp
+++ b/client_interface_impl.cpp
@@ -18,9 +18,8 @@
 
 #include <vector>
 
-#include <linux/if_ether.h>
-
 #include <android-base/logging.h>
+#include <utils/Timers.h>
 
 #include "wificond/client_interface_binder.h"
 #include "wificond/logging_utils.h"
@@ -32,6 +31,7 @@
 #include "wificond/scanning/scanner_impl.h"
 
 using android::net::wifi::IClientInterface;
+using android::net::wifi::ISendMgmtFrameEvent;
 using com::android::server::wifi::wificond::NativeScanResult;
 using android::sp;
 using android::wifi_system::InterfaceTool;
@@ -61,7 +61,7 @@
       LOG(INFO) << "Connect timeout";
     }
     client_interface_->is_associated_ = false;
-    client_interface_->bssid_.clear();
+    client_interface_->bssid_.fill(0);
   }
 }
 
@@ -81,18 +81,18 @@
       LOG(INFO) << "Associate timeout";
     }
     client_interface_->is_associated_ = false;
-    client_interface_->bssid_.clear();
+    client_interface_->bssid_.fill(0);
   }
 }
 
 void MlmeEventHandlerImpl::OnDisconnect(unique_ptr<MlmeDisconnectEvent> event) {
   client_interface_->is_associated_ = false;
-  client_interface_->bssid_.clear();
+  client_interface_->bssid_.fill(0);
 }
 
 void MlmeEventHandlerImpl::OnDisassociate(unique_ptr<MlmeDisassociateEvent> event) {
   client_interface_->is_associated_ = false;
-  client_interface_->bssid_.clear();
+  client_interface_->bssid_.fill(0);
 }
 
 
@@ -100,7 +100,7 @@
     uint32_t wiphy_index,
     const std::string& interface_name,
     uint32_t interface_index,
-    const std::vector<uint8_t>& interface_mac_addr,
+    const std::array<uint8_t, ETH_ALEN>& interface_mac_addr,
     InterfaceTool* if_tool,
     NetlinkUtils* netlink_utils,
     ScanUtils* scan_utils)
@@ -114,10 +114,25 @@
       offload_service_utils_(new OffloadServiceUtils()),
       mlme_event_handler_(new MlmeEventHandlerImpl(this)),
       binder_(new ClientInterfaceBinder(this)),
-      is_associated_(false) {
+      is_associated_(false),
+      frame_tx_in_progress_(false),
+      frame_tx_status_cookie_(0),
+      on_frame_tx_status_event_handler_([](bool was_acked) {}) {
   netlink_utils_->SubscribeMlmeEvent(
       interface_index_,
       mlme_event_handler_.get());
+
+  netlink_utils_->SubscribeFrameTxStatusEvent(
+      interface_index,
+      [this](uint64_t cookie, bool was_acked) {
+        if (frame_tx_in_progress_ && frame_tx_status_cookie_ == cookie) {
+          on_frame_tx_status_event_handler_(was_acked);
+          frame_tx_in_progress_ = false;
+          frame_tx_status_cookie_ = 0;
+          on_frame_tx_status_event_handler_ = [](bool was_acked) {};
+        }
+      });
+
   if (!netlink_utils_->GetWiphyInfo(wiphy_index_,
                                &band_info_,
                                &scan_capabilities_,
@@ -132,11 +147,15 @@
                              this,
                              scan_utils_,
                              offload_service_utils_);
+  // Need to set the interface up (especially in scan mode since wpa_supplicant
+  // is not started)
+  if_tool_->SetUpState(interface_name_.c_str(), true);
 }
 
 ClientInterfaceImpl::~ClientInterfaceImpl() {
   binder_->NotifyImplDead();
   scanner_->Invalidate();
+  netlink_utils_->UnsubscribeFrameTxStatusEvent(interface_index_);
   netlink_utils_->UnsubscribeMlmeEvent(interface_index_);
   if_tool_->SetUpState(interface_name_.c_str(), false);
 }
@@ -171,6 +190,8 @@
       << wiphy_features_.supports_high_accuracy_oneshot_scan << endl;
   *ss << "Device supports random MAC for scheduled scan: "
       << wiphy_features_.supports_random_mac_sched_scan << endl;
+  *ss << "Device supports sending management frames at specified MCS rate: "
+      << wiphy_features_.supports_tx_mgmt_frame_mcs << endl;
   *ss << "------- Dump End -------" << endl;
 }
 
@@ -207,25 +228,23 @@
   // Association frequency.
   out_signal_poll_results->push_back(
       static_cast<int32_t>(associate_freq_));
+  // Convert from 100kbit/s to Mbps.
+  out_signal_poll_results->push_back(
+      static_cast<int32_t>(station_info.station_rx_bitrate/10));
 
   return true;
 }
 
-const vector<uint8_t>& ClientInterfaceImpl::GetMacAddress() {
+const std::array<uint8_t, ETH_ALEN>& ClientInterfaceImpl::GetMacAddress() {
   return interface_mac_addr_;
 }
 
-bool ClientInterfaceImpl::SetMacAddress(const ::std::vector<uint8_t>& mac) {
-  if (mac.size() != ETH_ALEN) {
-    LOG(ERROR) << "Invalid MAC length " << mac.size();
-    return false;
-  }
+bool ClientInterfaceImpl::SetMacAddress(const std::array<uint8_t, ETH_ALEN>& mac) {
   if (!if_tool_->SetWifiUpState(false)) {
     LOG(ERROR) << "SetWifiUpState(false) failed.";
     return false;
   }
-  if (!if_tool_->SetMacAddress(interface_name_.c_str(),
-      {{mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]}})) {
+  if (!if_tool_->SetMacAddress(interface_name_.c_str(), mac)) {
     LOG(ERROR) << "SetMacAddress(" << interface_name_ << ", "
                << LoggingUtils::GetMacString(mac) << ") failed.";
     return false;
@@ -257,5 +276,36 @@
   return is_associated_;
 }
 
+void ClientInterfaceImpl::SendMgmtFrame(const vector<uint8_t>& frame,
+    const sp<ISendMgmtFrameEvent>& callback, int32_t mcs) {
+  if (mcs >= 0 && !wiphy_features_.supports_tx_mgmt_frame_mcs) {
+    callback->OnFailure(
+        ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED);
+    return;
+  }
+
+  uint64_t cookie;
+  if (!netlink_utils_->SendMgmtFrame(interface_index_, frame, mcs, &cookie)) {
+    callback->OnFailure(ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_UNKNOWN);
+    return;
+  }
+
+  frame_tx_in_progress_ = true;
+  frame_tx_status_cookie_ = cookie;
+  nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
+  on_frame_tx_status_event_handler_ =
+      [callback, start_time_ns](bool was_acked) {
+        if (was_acked) {
+          nsecs_t end_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
+          int32_t elapsed_time_ms = static_cast<int32_t>(
+              nanoseconds_to_milliseconds(end_time_ns - start_time_ns));
+          callback->OnAck(elapsed_time_ms);
+        } else {
+          callback->OnFailure(
+              ISendMgmtFrameEvent::SEND_MGMT_FRAME_ERROR_NO_ACK);
+        }
+      };
+}
+
 }  // namespace wificond
 }  // namespace android
diff --git a/client_interface_impl.h b/client_interface_impl.h
index 63077ec..e07b18b 100644
--- a/client_interface_impl.h
+++ b/client_interface_impl.h
@@ -17,13 +17,17 @@
 #ifndef WIFICOND_CLIENT_INTERFACE_IMPL_H_
 #define WIFICOND_CLIENT_INTERFACE_IMPL_H_
 
+#include <array>
 #include <string>
 
+#include <linux/if_ether.h>
+
 #include <android-base/macros.h>
 #include <utils/StrongPointer.h>
 #include <wifi_system/interface_tool.h>
 
 #include "android/net/wifi/IClientInterface.h"
+#include "android/net/wifi/ISendMgmtFrameEvent.h"
 #include "wificond/net/mlme_event_handler.h"
 #include "wificond/net/netlink_utils.h"
 #include "wificond/scanning/offload/offload_service_utils.h"
@@ -62,7 +66,7 @@
       uint32_t wiphy_index,
       const std::string& interface_name,
       uint32_t interface_index,
-      const std::vector<uint8_t>& interface_mac_addr,
+      const std::array<uint8_t, ETH_ALEN>& interface_mac_addr,
       android::wifi_system::InterfaceTool* if_tool,
       NetlinkUtils* netlink_utils,
       ScanUtils* scan_utils);
@@ -73,12 +77,16 @@
 
   bool GetPacketCounters(std::vector<int32_t>* out_packet_counters);
   bool SignalPoll(std::vector<int32_t>* out_signal_poll_results);
-  const std::vector<uint8_t>& GetMacAddress();
+  const std::array<uint8_t, ETH_ALEN>& GetMacAddress();
   const std::string& GetInterfaceName() const { return interface_name_; }
   const android::sp<ScannerImpl> GetScanner() { return scanner_; };
-  bool SetMacAddress(const ::std::vector<uint8_t>& mac);
+  bool SetMacAddress(const std::array<uint8_t, ETH_ALEN>& mac);
   virtual bool IsAssociated() const;
   void Dump(std::stringstream* ss) const;
+  void SendMgmtFrame(
+      const std::vector<uint8_t>& frame,
+      const sp<::android::net::wifi::ISendMgmtFrameEvent>& callback,
+      int32_t mcs);
 
  private:
   bool RefreshAssociateFreq();
@@ -86,7 +94,7 @@
   const uint32_t wiphy_index_;
   const std::string interface_name_;
   const uint32_t interface_index_;
-  const std::vector<uint8_t> interface_mac_addr_;
+  const std::array<uint8_t, ETH_ALEN> interface_mac_addr_;
   android::wifi_system::InterfaceTool* const if_tool_;
   NetlinkUtils* const netlink_utils_;
   ScanUtils* const scan_utils_;
@@ -97,7 +105,7 @@
 
   // Cached information for this connection.
   bool is_associated_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
   uint32_t associate_freq_;
 
   // Capability information for this wiphy/interface.
@@ -105,6 +113,11 @@
   ScanCapabilities scan_capabilities_;
   WiphyFeatures wiphy_features_;
 
+  // handler for frame tx status messages
+  bool frame_tx_in_progress_;
+  uint64_t frame_tx_status_cookie_;
+  std::function<void(bool was_acked)> on_frame_tx_status_event_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(ClientInterfaceImpl);
   friend class MlmeEventHandlerImpl;
 };
diff --git a/logging_utils.cpp b/logging_utils.cpp
index f717a50..189f0dd 100644
--- a/logging_utils.cpp
+++ b/logging_utils.cpp
@@ -16,19 +16,19 @@
 
 #include "wificond/logging_utils.h"
 
+#include <array>
 #include <iomanip>
-#include <vector>
 
 #include <android-base/macros.h>
 
+using std::array;
 using std::string;
 using std::stringstream;
-using std::vector;
 
 namespace android {
 namespace wificond {
 
-string LoggingUtils::GetMacString(const vector<uint8_t>& mac_address) {
+string LoggingUtils::GetMacString(const array<uint8_t, ETH_ALEN>& mac_address) {
   stringstream ss;
   for (const uint8_t& b : mac_address) {
     ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(b);
diff --git a/logging_utils.h b/logging_utils.h
index 1176d8a..86592b3 100644
--- a/logging_utils.h
+++ b/logging_utils.h
@@ -17,9 +17,11 @@
 #ifndef WIFICOND_LOGGING_UTILS_H_
 #define WIFICOND_LOGGING_UTILS_H_
 
-#include <vector>
+#include <array>
 #include <sstream>
 
+#include <linux/if_ether.h>
+
 #include <android-base/macros.h>
 
 #include "wificond/net/netlink_manager.h"
@@ -30,7 +32,7 @@
 class LoggingUtils {
  public:
   LoggingUtils() = default;
-  static std::string GetMacString(const std::vector<uint8_t>& mac_address);
+  static std::string GetMacString(const std::array<uint8_t, ETH_ALEN>& mac_address);
   static std::string GetBandwidthString(ChannelBandwidth bandwidth);
 
  private:
diff --git a/main.cpp b/main.cpp
index 9928f63..4e8586f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -39,9 +39,7 @@
 #include "wificond/server.h"
 
 using android::net::wifi::IWificond;
-using android::wifi_system::HostapdManager;
 using android::wifi_system::InterfaceTool;
-using android::wifi_system::SupplicantManager;
 using android::wificond::ipc_constants::kServiceName;
 using std::unique_ptr;
 
@@ -144,8 +142,6 @@
 
   unique_ptr<android::wificond::Server> server(new android::wificond::Server(
       unique_ptr<InterfaceTool>(new InterfaceTool),
-      unique_ptr<SupplicantManager>(new SupplicantManager()),
-      unique_ptr<HostapdManager>(new HostapdManager()),
       &netlink_utils,
       &scan_utils));
   RegisterServiceOrCrash(server.get());
diff --git a/net/mlme_event.cpp b/net/mlme_event.cpp
index 2a87a1d..1e58d38 100644
--- a/net/mlme_event.cpp
+++ b/net/mlme_event.cpp
@@ -23,6 +23,7 @@
 #include "wificond/net/kernel-header-latest/nl80211.h"
 #include "wificond/net/nl80211_packet.h"
 
+using std::array;
 using std::unique_ptr;
 using std::vector;
 
@@ -33,7 +34,7 @@
 
 bool GetCommonFields(const NL80211Packet* packet,
                      uint32_t* if_index,
-                     vector<uint8_t>* bssid) {
+                     array<uint8_t, ETH_ALEN>* bssid) {
   if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, if_index)) {
      LOG(ERROR) << "Failed to get NL80211_ATTR_IFINDEX";
      return false;
diff --git a/net/mlme_event.h b/net/mlme_event.h
index cc332fc..79d25e3 100644
--- a/net/mlme_event.h
+++ b/net/mlme_event.h
@@ -17,8 +17,10 @@
 #ifndef WIFICOND_NET_MLME_EVENT_H_
 #define WIFICOND_NET_MLME_EVENT_H_
 
+#include <array>
 #include <memory>
-#include <vector>
+
+#include <linux/if_ether.h>
 
 #include <android-base/macros.h>
 
@@ -32,7 +34,7 @@
   static std::unique_ptr<MlmeConnectEvent> InitFromPacket(
       const NL80211Packet* packet);
   // Returns the BSSID of the associated AP.
-  const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+  const std::array<uint8_t, ETH_ALEN>& GetBSSID() const { return bssid_; }
   // Get the status code of this connect event.
   // 0 = success, non-zero = failure.
   // Status codes definition: IEEE 802.11-2012, 8.4.1.9, Table 8-37
@@ -44,7 +46,7 @@
   MlmeConnectEvent() = default;
 
   uint32_t interface_index_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
   uint16_t status_code_;
   bool is_timeout_;
 
@@ -56,7 +58,7 @@
   static std::unique_ptr<MlmeAssociateEvent> InitFromPacket(
       const NL80211Packet* packet);
   // Returns the BSSID of the associated AP.
-  const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+  const std::array<uint8_t, ETH_ALEN>& GetBSSID() const { return bssid_; }
   // Get the status code of this associate event.
   // 0 = success, non-zero = failure.
   // Status codes definition: IEEE 802.11-2012, 8.4.1.9, Table 8-37
@@ -68,7 +70,7 @@
   MlmeAssociateEvent() = default;
 
   uint32_t interface_index_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
   uint16_t status_code_;
   bool is_timeout_;
 
@@ -80,14 +82,14 @@
   static std::unique_ptr<MlmeRoamEvent> InitFromPacket(
       const NL80211Packet* packet);
   // Returns the BSSID of the associated AP.
-  const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+  const std::array<uint8_t, ETH_ALEN>& GetBSSID() const { return bssid_; }
   uint32_t GetInterfaceIndex() const { return interface_index_; }
 
  private:
   MlmeRoamEvent() = default;
 
   uint32_t interface_index_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
 
   DISALLOW_COPY_AND_ASSIGN(MlmeRoamEvent);
 };
@@ -102,7 +104,7 @@
   MlmeDisconnectEvent() = default;
 
   uint32_t interface_index_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
 
   DISALLOW_COPY_AND_ASSIGN(MlmeDisconnectEvent);
 };
@@ -116,7 +118,7 @@
   MlmeDisassociateEvent() = default;
 
   uint32_t interface_index_;
-  std::vector<uint8_t> bssid_;
+  std::array<uint8_t, ETH_ALEN> bssid_;
 
   DISALLOW_COPY_AND_ASSIGN(MlmeDisassociateEvent);
 };
diff --git a/net/netlink_manager.cpp b/net/netlink_manager.cpp
index f9c8997..0238f0b 100644
--- a/net/netlink_manager.cpp
+++ b/net/netlink_manager.cpp
@@ -33,6 +33,7 @@
 #include "net/nl80211_packet.h"
 
 using android::base::unique_fd;
+using std::array;
 using std::placeholders::_1;
 using std::string;
 using std::unique_ptr;
@@ -534,7 +535,7 @@
     }
     const auto handler = on_station_event_handler_.find(if_index);
     if (handler != on_station_event_handler_.end()) {
-      vector<uint8_t> mac_address;
+      array<uint8_t, ETH_ALEN> mac_address;
       if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &mac_address)) {
         LOG(WARNING) << "Failed to get mac address from station event";
         return;
@@ -551,6 +552,10 @@
     OnChannelSwitchEvent(std::move(packet));
     return;
   }
+  if (command == NL80211_CMD_FRAME_TX_STATUS) {
+    OnFrameTxStatusEvent(std::move(packet));
+    return;
+  }
 }
 
 void NetlinkManager::OnRegChangeEvent(unique_ptr<const NL80211Packet> packet) {
@@ -727,6 +732,31 @@
     }
 }
 
+void NetlinkManager::OnFrameTxStatusEvent(
+    unique_ptr<const NL80211Packet> packet) {
+
+  uint32_t if_index;
+  if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
+    LOG(WARNING) << "Failed to get NL80211_ATTR_IFINDEX"
+                 << "from NL80211_CMD_FRAME_TX_STATUS event";
+    return;
+  }
+
+  uint64_t cookie;
+  if (!packet->GetAttributeValue(NL80211_ATTR_COOKIE, &cookie)) {
+    LOG(WARNING) << "Failed to get NL80211_ATTR_COOKIE"
+                 << "from NL80211_CMD_FRAME_TX_STATUS event";
+    return;
+  }
+
+  bool was_acked = packet->HasAttribute(NL80211_ATTR_ACK);
+
+  const auto handler = on_frame_tx_status_event_handler_.find(if_index);
+  if (handler != on_frame_tx_status_event_handler_.end()) {
+    handler->second(cookie, was_acked);
+  }
+}
+
 void NetlinkManager::SubscribeStationEvent(
     uint32_t interface_index,
     OnStationEventHandler handler) {
@@ -789,5 +819,14 @@
   on_sched_scan_result_ready_handler_.erase(interface_index);
 }
 
+void NetlinkManager::SubscribeFrameTxStatusEvent(
+    uint32_t interface_index, OnFrameTxStatusEventHandler handler) {
+  on_frame_tx_status_event_handler_[interface_index] = handler;
+}
+
+void NetlinkManager::UnsubscribeFrameTxStatusEvent(uint32_t interface_index) {
+  on_frame_tx_status_event_handler_.erase(interface_index);
+}
+
 }  // namespace wificond
 }  // namespace android
diff --git a/net/netlink_manager.h b/net/netlink_manager.h
index f8817f4..98db5ae 100644
--- a/net/netlink_manager.h
+++ b/net/netlink_manager.h
@@ -17,10 +17,13 @@
 #ifndef WIFICOND_NET_NETLINK_MANAGER_H_
 #define WIFICOND_NET_NETLINK_MANAGER_H_
 
+#include <array>
 #include <functional>
 #include <map>
 #include <memory>
 
+#include <linux/if_ether.h>
+
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
 
@@ -113,7 +116,14 @@
 // |mac_address| is the station mac address associated with this event.
 typedef std::function<void(
     StationEvent event,
-    const std::vector<uint8_t>& mac_address)> OnStationEventHandler;
+    const std::array<uint8_t, ETH_ALEN>& mac_address)> OnStationEventHandler;
+
+// This describes a type of function handling frame tx status events.
+// |cookie| specifies the cookie of the transmitted frame that this status
+// event corresponds to.
+// |was_acked| reports whether the transmitted frame was ACKed.
+typedef std::function<void(
+    uint64_t cookie, bool was_acked)> OnFrameTxStatusEventHandler;
 
 class NetlinkManager {
  public:
@@ -255,6 +265,13 @@
   // Cancel the sign-up of receiving channel events.
   virtual void UnsubscribeChannelSwitchEvent(uint32_t interface_index);
 
+  // Sign up to be notified of frame tx status events.
+  virtual void SubscribeFrameTxStatusEvent(
+      uint32_t interface_index, OnFrameTxStatusEventHandler handler);
+
+  // Cancel the sign-up of receiving frame tx status events.
+  virtual void UnsubscribeFrameTxStatusEvent(uint32_t interface_index);
+
  private:
   bool SetupSocket(android::base::unique_fd* netlink_fd);
   bool WatchSocket(android::base::unique_fd* netlink_fd);
@@ -267,6 +284,7 @@
   void OnScanResultsReady(std::unique_ptr<const NL80211Packet> packet);
   void OnSchedScanResultsReady(std::unique_ptr<const NL80211Packet> packet);
   void OnChannelSwitchEvent(std::unique_ptr<const NL80211Packet> packet);
+  void OnFrameTxStatusEvent(std::unique_ptr<const NL80211Packet> packet);
 
   // This handler revceives mapping from NL80211 family name to family id,
   // as well as mapping from group name to group id.
@@ -303,6 +321,10 @@
   std::map<uint32_t, OnStationEventHandler> on_station_event_handler_;
   std::map<uint32_t, OnChannelSwitchEventHandler> on_channel_switch_event_handler_;
 
+  // mapping from interface_index to frame tx status event handler
+  std::map<uint32_t, OnFrameTxStatusEventHandler>
+      on_frame_tx_status_event_handler_;
+
   // Mapping from family name to family id, and group name to group id.
   std::map<std::string, MessageType> message_types_;
 
diff --git a/net/netlink_utils.cpp b/net/netlink_utils.cpp
index b47d542..f395d92 100644
--- a/net/netlink_utils.cpp
+++ b/net/netlink_utils.cpp
@@ -16,6 +16,8 @@
 
 #include "wificond/net/netlink_utils.h"
 
+#include <array>
+#include <algorithm>
 #include <bitset>
 #include <map>
 #include <string>
@@ -30,6 +32,7 @@
 #include "wificond/net/mlme_event_handler.h"
 #include "wificond/net/nl80211_packet.h"
 
+using std::array;
 using std::make_pair;
 using std::make_unique;
 using std::map;
@@ -85,6 +88,11 @@
   supports_high_accuracy_oneshot_scan =
       IsExtFeatureFlagSet(ext_feature_flags_bytes,
                           NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
+  // TODO (b/112029045) check if sending frame at specified MCS is supported
+  supports_tx_mgmt_frame_mcs = false;
+  supports_ext_sched_scan_relative_rssi =
+      IsExtFeatureFlagSet(ext_feature_flags_bytes,
+                          NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI);
 }
 
 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
@@ -208,7 +216,7 @@
       continue;
     }
 
-    vector<uint8_t> if_mac_addr;
+    array<uint8_t, ETH_ALEN> if_mac_addr;
     if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
       LOG(WARNING) << "Failed to get interface mac address";
       continue;
@@ -467,7 +475,7 @@
 }
 
 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
-                                  const vector<uint8_t>& mac_address,
+                                  const array<uint8_t, ETH_ALEN>& mac_address,
                                   StationInfo* out_station_info) {
   NL80211Packet get_station(
       netlink_manager_->GetFamilyId(),
@@ -476,8 +484,8 @@
       getpid());
   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
                                                  interface_index));
-  get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC,
-                                                        mac_address));
+  get_station.AddAttribute(NL80211Attr<array<uint8_t, ETH_ALEN>>(
+      NL80211_ATTR_MAC, mac_address));
 
   unique_ptr<const NL80211Packet> response;
   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
@@ -510,19 +518,26 @@
     return false;
   }
   NL80211NestedAttr tx_bitrate_attr(0);
-  if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
+  uint32_t tx_bitrate = 0;
+  if (sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
                             &tx_bitrate_attr)) {
-    LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE";
-    return false;
-  }
-  uint32_t tx_bitrate;
-  if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
+    if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
                                          &tx_bitrate)) {
-    LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32";
-    return false;
+      // Return invalid tx rate to avoid breaking the get station cmd
+      tx_bitrate = 0;
+    }
   }
-
-  *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi);
+  NL80211NestedAttr rx_bitrate_attr(0);
+  uint32_t rx_bitrate = 0;
+  if (sta_info.GetAttribute(NL80211_STA_INFO_RX_BITRATE,
+                            &rx_bitrate_attr)) {
+    if (!rx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
+                                         &rx_bitrate)) {
+      // Return invalid rx rate to avoid breaking the get station cmd
+      rx_bitrate = 0;
+    }
+  }
+  *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi, rx_bitrate);
   return true;
 }
 
@@ -600,6 +615,40 @@
   return true;
 }
 
+bool NetlinkUtils::SendMgmtFrame(uint32_t interface_index,
+    const vector<uint8_t>& frame, int32_t mcs, uint64_t* out_cookie) {
+
+  NL80211Packet send_mgmt_frame(
+      netlink_manager_->GetFamilyId(),
+      NL80211_CMD_FRAME,
+      netlink_manager_->GetSequenceNumber(),
+      getpid());
+
+  send_mgmt_frame.AddAttribute(
+      NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
+
+  send_mgmt_frame.AddAttribute(
+      NL80211Attr<vector<uint8_t>>(NL80211_ATTR_FRAME, frame));
+
+  if (mcs >= 0) {
+    // TODO (b/112029045) if mcs >= 0, add MCS attribute
+  }
+
+  unique_ptr<const NL80211Packet> response;
+  if (!netlink_manager_->SendMessageAndGetSingleResponse(
+      send_mgmt_frame, &response)) {
+    LOG(ERROR) << "NL80211_CMD_FRAME failed";
+    return false;
+  }
+
+  if (!response->GetAttributeValue(NL80211_ATTR_COOKIE, out_cookie)) {
+    LOG(ERROR) << "Get NL80211_ATTR_COOKIE failed";
+    return false;
+  }
+
+  return true;
+}
+
 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
                                       MlmeEventHandler* handler) {
   netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
@@ -637,6 +686,14 @@
   netlink_manager_->UnsubscribeChannelSwitchEvent(interface_index);
 }
 
+void NetlinkUtils::SubscribeFrameTxStatusEvent(
+    uint32_t interface_index, OnFrameTxStatusEventHandler handler) {
+  netlink_manager_->SubscribeFrameTxStatusEvent(interface_index, handler);
+}
+
+void NetlinkUtils::UnsubscribeFrameTxStatusEvent(uint32_t interface_index) {
+  netlink_manager_->UnsubscribeFrameTxStatusEvent(interface_index);
+}
 
 }  // namespace wificond
 }  // namespace android
diff --git a/net/netlink_utils.h b/net/netlink_utils.h
index 5e840b6..b3c34d3 100644
--- a/net/netlink_utils.h
+++ b/net/netlink_utils.h
@@ -17,9 +17,13 @@
 #ifndef WIFICOND_NET_NETLINK_UTILS_H_
 #define WIFICOND_NET_NETLINK_UTILS_H_
 
+#include <array>
+#include <functional>
 #include <string>
 #include <vector>
 
+#include <linux/if_ether.h>
+
 #include <android-base/macros.h>
 
 #include "wificond/net/kernel-header-latest/nl80211.h"
@@ -30,18 +34,18 @@
 
 struct InterfaceInfo {
   InterfaceInfo() = default;
-  InterfaceInfo(uint32_t index_,
-                const std::string name_,
-                const std::vector<uint8_t> mac_address_)
-      : index(index_),
-        name(name_),
-        mac_address(mac_address_) {}
+  InterfaceInfo(uint32_t index,
+                const std::string& name,
+                const std::array<uint8_t, ETH_ALEN>& mac_address)
+      : index(index),
+        name(name),
+        mac_address(mac_address) {}
   // Index of this interface.
   uint32_t index;
   // Name of this interface.
   std::string name;
   // MAC address of this interface.
-  std::vector<uint8_t> mac_address;
+  std::array<uint8_t, ETH_ALEN> mac_address;
 };
 
 struct BandInfo {
@@ -96,7 +100,8 @@
         supports_random_mac_sched_scan(false),
         supports_low_span_oneshot_scan(false),
         supports_low_power_oneshot_scan(false),
-        supports_high_accuracy_oneshot_scan(false) {}
+        supports_high_accuracy_oneshot_scan(false),
+        supports_tx_mgmt_frame_mcs(false) {}
   WiphyFeatures(uint32_t feature_flags,
                 const std::vector<uint8_t>& ext_feature_flags_bytes);
   // This device/driver supports using a random MAC address during scan
@@ -111,6 +116,11 @@
   bool supports_low_power_oneshot_scan;
   // This device/driver supports performing high-accuracy one-shot scans.
   bool supports_high_accuracy_oneshot_scan;
+  // This device/driver supports sending a management frame at a specified MCS.
+  bool supports_tx_mgmt_frame_mcs;
+  // This device/driver supports sched_scan for reporting BSSs
+  // with better RSSI than the current connected BSS
+  bool supports_ext_sched_scan_relative_rssi;
   // There are other flags included in NL80211_ATTR_FEATURE_FLAGS.
   // We will add them once we find them useful.
 };
@@ -120,11 +130,13 @@
   StationInfo(uint32_t station_tx_packets_,
               uint32_t station_tx_failed_,
               uint32_t station_tx_bitrate_,
-              int8_t current_rssi_)
+              int8_t current_rssi_,
+              uint32_t station_rx_bitrate_)
       : station_tx_packets(station_tx_packets_),
         station_tx_failed(station_tx_failed_),
         station_tx_bitrate(station_tx_bitrate_),
-        current_rssi(current_rssi_) {}
+        current_rssi(current_rssi_),
+        station_rx_bitrate(station_rx_bitrate_) {}
   // Number of successfully transmitted packets.
   int32_t station_tx_packets;
   // Number of tramsmission failures.
@@ -133,6 +145,8 @@
   uint32_t station_tx_bitrate;
   // Current signal strength.
   int8_t current_rssi;
+  // Last Received unicast packet bit rate in 100kbit/s.
+  uint32_t station_rx_bitrate;
   // There are many other counters/parameters included in station info.
   // We will add them once we find them useful.
 };
@@ -186,7 +200,7 @@
   // |*out_station_info]| is the struct of available station information.
   // Returns true on success.
   virtual bool GetStationInfo(uint32_t interface_index,
-                              const std::vector<uint8_t>& mac_address,
+                              const std::array<uint8_t, ETH_ALEN>& mac_address,
                               StationInfo* out_station_info);
 
   // Get a bitmap for nl80211 protocol features,
@@ -244,6 +258,16 @@
   // Cancel the sign-up of receiving channel switch events.
   virtual void UnsubscribeChannelSwitchEvent(uint32_t interface_index);
 
+  // Sign up to be notified of frame tx status events.
+  virtual void SubscribeFrameTxStatusEvent(
+      uint32_t interface_index, OnFrameTxStatusEventHandler handler);
+
+  // Cancel the sign-up of receiving frame tx status events.
+  virtual void UnsubscribeFrameTxStatusEvent(uint32_t interface_index);
+
+  virtual bool SendMgmtFrame(uint32_t interface_index,
+    const std::vector<uint8_t>& frame, int32_t mcs, uint64_t* out_cookie);
+
   // Visible for testing.
   bool supports_split_wiphy_dump_;
 
diff --git a/net/nl80211_attribute.h b/net/nl80211_attribute.h
index 04fc890..1493c56 100644
--- a/net/nl80211_attribute.h
+++ b/net/nl80211_attribute.h
@@ -113,6 +113,23 @@
   std::vector<uint8_t> GetValue() const;
 }; // class NL80211Attr for raw data
 
+template <size_t N>
+class NL80211Attr<std::array<uint8_t, N>> : public BaseNL80211Attr {
+ public:
+  NL80211Attr(int id, const std::array<uint8_t, N>& raw_buffer)
+      : BaseNL80211Attr(
+          id, std::vector<uint8_t>(raw_buffer.begin(), raw_buffer.end())) {}
+  explicit NL80211Attr(const std::vector<uint8_t>& data) {
+    data_ = data;
+  }
+  ~NL80211Attr() override = default;
+  std::array<uint8_t, N> GetValue() const {
+    std::array<uint8_t, N> arr;
+    std::copy_n(data_.data() + NLA_HDRLEN, N, arr.begin());
+    return arr;
+  }
+}; // class NL80211Attr for fixed size array
+
 template <>
 class NL80211Attr<std::string> : public BaseNL80211Attr {
  public:
diff --git a/scanning/offload/offload_scan_utils.cpp b/scanning/offload/offload_scan_utils.cpp
index 1446f76..d476507 100644
--- a/scanning/offload/offload_scan_utils.cpp
+++ b/scanning/offload/offload_scan_utils.cpp
@@ -43,7 +43,7 @@
     single_scan_result.ssid.assign(scan_result[i].networkInfo.ssid.begin(),
                                    scan_result[i].networkInfo.ssid.end());
     for (size_t j = 0; j < scan_result[i].bssid.elementCount(); j++) {
-      single_scan_result.bssid.push_back(scan_result[i].bssid[j]);
+      single_scan_result.bssid.at(j) = scan_result[i].bssid[j];
     }
     single_scan_result.frequency = scan_result[i].frequency;
     single_scan_result.signal_mbm = scan_result[i].rssi;
diff --git a/scanning/pno_network.cpp b/scanning/pno_network.cpp
index d63f6b3..02f8e5f 100644
--- a/scanning/pno_network.cpp
+++ b/scanning/pno_network.cpp
@@ -31,6 +31,7 @@
 status_t PnoNetwork::writeToParcel(::android::Parcel* parcel) const {
   RETURN_IF_FAILED(parcel->writeInt32(is_hidden_ ? 1 : 0));
   RETURN_IF_FAILED(parcel->writeByteVector(ssid_));
+  RETURN_IF_FAILED(parcel->writeInt32Vector(frequencies_));
   return ::android::OK;
 }
 
@@ -39,6 +40,7 @@
   RETURN_IF_FAILED(parcel->readInt32(&is_hidden));
   is_hidden_ = (is_hidden != 0);
   RETURN_IF_FAILED(parcel->readByteVector(&ssid_));
+  RETURN_IF_FAILED(parcel->readInt32Vector(&frequencies_));
   return ::android::OK;
 }
 
diff --git a/scanning/pno_network.h b/scanning/pno_network.h
index 6156c6c..bd5d6cb 100644
--- a/scanning/pno_network.h
+++ b/scanning/pno_network.h
@@ -40,6 +40,7 @@
 
   bool is_hidden_;
   std::vector<uint8_t> ssid_;
+  std::vector<int32_t> frequencies_;
 };
 
 }  // namespace wificond
diff --git a/scanning/scan_result.cpp b/scanning/scan_result.cpp
index 7df4daa..fa85981 100644
--- a/scanning/scan_result.cpp
+++ b/scanning/scan_result.cpp
@@ -16,6 +16,8 @@
 
 #include "wificond/scanning/scan_result.h"
 
+#include <algorithm>
+
 #include <android-base/logging.h>
 
 #include "wificond/logging_utils.h"
@@ -32,7 +34,7 @@
 namespace wificond {
 
 NativeScanResult::NativeScanResult(std::vector<uint8_t>& ssid_,
-                                   std::vector<uint8_t>& bssid_,
+                                   std::array<uint8_t, ETH_ALEN>& bssid_,
                                    std::vector<uint8_t>& info_element_,
                                    uint32_t frequency_,
                                    int32_t signal_mbm_,
@@ -53,7 +55,8 @@
 
 status_t NativeScanResult::writeToParcel(::android::Parcel* parcel) const {
   RETURN_IF_FAILED(parcel->writeByteVector(ssid));
-  RETURN_IF_FAILED(parcel->writeByteVector(bssid));
+  RETURN_IF_FAILED(parcel->writeByteVector(
+      std::vector<uint8_t>(bssid.begin(), bssid.end())));
   RETURN_IF_FAILED(parcel->writeByteVector(info_element));
   RETURN_IF_FAILED(parcel->writeUint32(frequency));
   RETURN_IF_FAILED(parcel->writeInt32(signal_mbm));
@@ -74,7 +77,16 @@
 
 status_t NativeScanResult::readFromParcel(const ::android::Parcel* parcel) {
   RETURN_IF_FAILED(parcel->readByteVector(&ssid));
-  RETURN_IF_FAILED(parcel->readByteVector(&bssid));
+  {
+    std::vector<uint8_t> bssid_vec;
+    RETURN_IF_FAILED(parcel->readByteVector(&bssid_vec));
+    if (bssid_vec.size() != ETH_ALEN) {
+      LOG(ERROR) << "bssid length expected " << ETH_ALEN << " bytes, but got "
+                 << bssid_vec.size() << " bytes";
+      return ::android::BAD_VALUE;
+    }
+    std::copy_n(bssid_vec.begin(), ETH_ALEN, bssid.begin());
+  }
   RETURN_IF_FAILED(parcel->readByteVector(&info_element));
   RETURN_IF_FAILED(parcel->readUint32(&frequency));
   RETURN_IF_FAILED(parcel->readInt32(&signal_mbm));
diff --git a/scanning/scan_result.h b/scanning/scan_result.h
index 4e7df47..bd9dc98 100644
--- a/scanning/scan_result.h
+++ b/scanning/scan_result.h
@@ -17,8 +17,11 @@
 #ifndef WIFICOND_SCANNING_SCAN_RESULT_H_
 #define WIFICOND_SCANNING_SCAN_RESULT_H_
 
+#include <array>
 #include <vector>
 
+#include <linux/if_ether.h>
+
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 
@@ -35,7 +38,7 @@
  public:
   NativeScanResult() = default;
   NativeScanResult(std::vector<uint8_t>& ssid,
-                   std::vector<uint8_t>& bssid,
+                   std::array<uint8_t, ETH_ALEN>& bssid,
                    std::vector<uint8_t>& info_element,
                    uint32_t frequency,
                    int32_t signal_mbm,
@@ -51,7 +54,7 @@
   // SSID of the BSS.
   std::vector<uint8_t> ssid;
   // BSSID of the BSS.
-  std::vector<uint8_t> bssid;
+  std::array<uint8_t, ETH_ALEN> bssid;
   // Binary array containing the raw information elements from the probe
   // response/beacon.
   std::vector<uint8_t> info_element;
diff --git a/scanning/scan_utils.cpp b/scanning/scan_utils.cpp
index 708e0b4..65f8f8c 100644
--- a/scanning/scan_utils.cpp
+++ b/scanning/scan_utils.cpp
@@ -17,9 +17,11 @@
 #include "android/net/wifi/IWifiScannerImpl.h"
 #include "wificond/scanning/scan_utils.h"
 
+#include <array>
 #include <vector>
 
 #include <linux/netlink.h>
+#include <linux/if_ether.h>
 
 #include <android-base/logging.h>
 
@@ -31,6 +33,7 @@
 using android::net::wifi::IWifiScannerImpl;
 using com::android::server::wifi::wificond::NativeScanResult;
 using com::android::server::wifi::wificond::RadioChainInfo;
+using std::array;
 using std::unique_ptr;
 using std::vector;
 
@@ -134,7 +137,7 @@
   }
   NL80211NestedAttr bss(0);
   if (packet->GetAttribute(NL80211_ATTR_BSS, &bss)) {
-    vector<uint8_t> bssid;
+    array<uint8_t, ETH_ALEN> bssid;
     if (!bss.GetAttributeValue(NL80211_BSS_BSSID, &bssid)) {
       LOG(ERROR) << "Failed to get BSSID from scan result packet";
       return false;
@@ -402,8 +405,7 @@
     const SchedScanIntervalSetting& interval_setting,
     int32_t rssi_threshold_2g,
     int32_t rssi_threshold_5g,
-    bool request_random_mac,
-    bool request_low_power,
+    const SchedScanReqFlags& req_flags,
     const std::vector<std::vector<uint8_t>>& scan_ssids,
     const std::vector<std::vector<uint8_t>>& match_ssids,
     const std::vector<uint32_t>& freqs,
@@ -441,15 +443,18 @@
   start_sched_scan.AddAttribute(scan_match_attr);
 
   // We set 5g threshold for default and ajust threshold for 2g band.
-  struct nl80211_bss_select_rssi_adjust rssi_adjust;
-  rssi_adjust.band = NL80211_BAND_2GHZ;
-  rssi_adjust.delta = static_cast<int8_t>(rssi_threshold_2g - rssi_threshold_5g);
-  NL80211Attr<vector<uint8_t>> rssi_adjust_attr(
-      NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
-      vector<uint8_t>(
-          reinterpret_cast<uint8_t*>(&rssi_adjust),
-          reinterpret_cast<uint8_t*>(&rssi_adjust) + sizeof(rssi_adjust)));
-  start_sched_scan.AddAttribute(rssi_adjust_attr);
+  // check sched_scan supported before set NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST attribute.
+  if (req_flags.request_sched_scan_relative_rssi) {
+      struct nl80211_bss_select_rssi_adjust rssi_adjust;
+      rssi_adjust.band = NL80211_BAND_2GHZ;
+      rssi_adjust.delta = static_cast<int8_t>(rssi_threshold_2g - rssi_threshold_5g);
+      NL80211Attr<vector<uint8_t>> rssi_adjust_attr(
+          NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+          vector<uint8_t>(
+              reinterpret_cast<uint8_t*>(&rssi_adjust),
+              reinterpret_cast<uint8_t*>(&rssi_adjust) + sizeof(rssi_adjust)));
+      start_sched_scan.AddAttribute(rssi_adjust_attr);
+  }
 
   // Append all attributes to the NL80211_CMD_START_SCHED_SCAN packet.
   start_sched_scan.AddAttribute(
@@ -485,10 +490,10 @@
                               interval_setting.final_interval_ms));
   }
   uint32_t scan_flags = 0;
-  if (request_random_mac) {
+  if (req_flags.request_random_mac) {
     scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
   }
-  if (request_low_power) {
+  if (req_flags.request_low_power) {
     scan_flags |= NL80211_SCAN_FLAG_LOW_POWER;
   }
   if (scan_flags) {
diff --git a/scanning/scan_utils.h b/scanning/scan_utils.h
index a33023b..d160123 100644
--- a/scanning/scan_utils.h
+++ b/scanning/scan_utils.h
@@ -56,6 +56,12 @@
   uint32_t final_interval_ms{0};
 };
 
+struct SchedScanReqFlags {
+  bool request_random_mac;
+  bool request_low_power;
+  bool request_sched_scan_relative_rssi;
+};
+
 // Provides scanning helper functions.
 class ScanUtils {
  public:
@@ -111,6 +117,9 @@
   // - |request_low_power|: If true, prioritize power consumption over
   // other scan performance attributes.
   // Requires |supports_low_power_oneshot_scan|.
+  // - |request_sched_scan_relative_rssi| is sched_scan flag for better BSS's from connected BSS.
+  // If |request_sched_scan_relative_rssi| is true, it will fill scan rssi adjust to
+  // get BSS's with better RSSI from connected BSS.
   // - |scan_ssids| is the list of ssids to actively scan for.
   // If |scan_ssids| is an empty vector, it will do a passive scan.
   // If |scan_ssids| contains an empty string, it will a scan for all ssids.
@@ -126,8 +135,7 @@
       const SchedScanIntervalSetting& interval_setting,
       int32_t rssi_threshold_2g,
       int32_t rssi_threshold_5g,
-      bool request_random_mac,
-      bool request_low_power,
+      const SchedScanReqFlags& req_flags,
       const std::vector<std::vector<uint8_t>>& scan_ssids,
       const std::vector<std::vector<uint8_t>>& match_ssids,
       const std::vector<uint32_t>& freqs,
diff --git a/scanning/scanner_impl.cpp b/scanning/scanner_impl.cpp
index eb15178..f2953d8 100644
--- a/scanning/scanner_impl.cpp
+++ b/scanning/scanner_impl.cpp
@@ -16,6 +16,7 @@
 
 #include "wificond/scanning/scanner_impl.h"
 
+#include <set>
 #include <string>
 #include <vector>
 
@@ -57,6 +58,10 @@
   }
   return {};
 }
+
+constexpr const int kPercentNetworksWithFreq = 30;
+constexpr const int kPnoScanDefaultFreqs[] = {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452,
+    2457, 2462, 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805};
 } // namespace
 
 namespace android {
@@ -243,6 +248,8 @@
   const uint8_t kNetworkFlagsDefault = 0;
   vector<vector<uint8_t>> skipped_scan_ssids;
   vector<vector<uint8_t>> skipped_match_ssids;
+  std::set<int32_t> unique_frequencies;
+  int num_networks_no_freqs = 0;
   for (auto& network : pno_settings.pno_networks_) {
     // Add hidden network ssid.
     if (network.is_hidden_) {
@@ -261,8 +268,25 @@
     }
     match_ssids->push_back(network.ssid_);
     match_security->push_back(kNetworkFlagsDefault);
+
+    // build the set of unique frequencies to scan for.
+    for (const auto& frequency : network.frequencies_) {
+      unique_frequencies.insert(frequency);
+    }
+    if (network.frequencies_.empty()) {
+      num_networks_no_freqs++;
+    }
   }
 
+  // Also scan the default frequencies if there is frequency data passed down but more than 30% of
+  // networks don't have frequency data.
+  if (unique_frequencies.size() > 0 && num_networks_no_freqs * 100 / match_ssids->size()
+      > kPercentNetworksWithFreq) {
+    unique_frequencies.insert(std::begin(kPnoScanDefaultFreqs), std::end(kPnoScanDefaultFreqs));
+  }
+  for (const auto& frequency : unique_frequencies) {
+    freqs->push_back(frequency);
+  }
   LogSsidList(skipped_scan_ssids, "Skip scan ssid for pno scan");
   LogSsidList(skipped_match_ssids, "Skip match ssid for pno scan");
 }
@@ -288,13 +312,18 @@
   // Always request a low power scan for PNO, if device supports it.
   bool request_low_power = wiphy_features_.supports_low_power_oneshot_scan;
 
+  bool request_sched_scan_relative_rssi = wiphy_features_.supports_ext_sched_scan_relative_rssi;
+
   int error_code = 0;
+  struct SchedScanReqFlags req_flags = {};
+  req_flags.request_random_mac = request_random_mac;
+  req_flags.request_low_power = request_low_power;
+  req_flags.request_sched_scan_relative_rssi = request_sched_scan_relative_rssi;
   if (!scan_utils_->StartScheduledScan(interface_index_,
                                        GenerateIntervalSetting(pno_settings),
                                        pno_settings.min_2g_rssi_,
                                        pno_settings.min_5g_rssi_,
-                                       request_random_mac,
-                                       request_low_power,
+                                       req_flags,
                                        scan_ssids,
                                        match_ssids,
                                        freqs,
@@ -303,7 +332,16 @@
     CHECK(error_code != ENODEV) << "Driver is in a bad state, restarting wificond";
     return false;
   }
-  LOG(INFO) << "Pno scan started";
+  string freq_string;
+  if (freqs.empty()) {
+    freq_string = "for all supported frequencies";
+  } else {
+    freq_string = "for frequencies: ";
+    for (uint32_t f : freqs) {
+      freq_string += std::to_string(f) + ", ";
+    }
+  }
+  LOG(INFO) << "Pno scan started " << freq_string;
   pno_scan_started_ = true;
   return true;
 }
diff --git a/server.cpp b/server.cpp
index 7db0f75..b592dfe 100644
--- a/server.cpp
+++ b/server.cpp
@@ -35,9 +35,7 @@
 using android::net::wifi::IApInterface;
 using android::net::wifi::IClientInterface;
 using android::net::wifi::IInterfaceEventCallback;
-using android::wifi_system::HostapdManager;
 using android::wifi_system::InterfaceTool;
-using android::wifi_system::SupplicantManager;
 
 using std::endl;
 using std::placeholders::_1;
@@ -56,13 +54,9 @@
 }  // namespace
 
 Server::Server(unique_ptr<InterfaceTool> if_tool,
-               unique_ptr<SupplicantManager> supplicant_manager,
-               unique_ptr<HostapdManager> hostapd_manager,
                NetlinkUtils* netlink_utils,
                ScanUtils* scan_utils)
     : if_tool_(std::move(if_tool)),
-      supplicant_manager_(std::move(supplicant_manager)),
-      hostapd_manager_(std::move(hostapd_manager)),
       netlink_utils_(netlink_utils),
       scan_utils_(scan_utils) {
 }
@@ -105,8 +99,7 @@
       interface.name,
       interface.index,
       netlink_utils_,
-      if_tool_.get(),
-      hostapd_manager_.get()));
+      if_tool_.get()));
   *created_interface = ap_interface->GetBinder();
   BroadcastApInterfaceReady(ap_interface->GetBinder());
   ap_interfaces_[iface_name] = std::move(ap_interface);
@@ -178,16 +171,6 @@
   return Status::ok();
 }
 
-Status Server::enableSupplicant(bool* success) {
-  *success = supplicant_manager_->StartSupplicant();
-  return Status::ok();
-}
-
-Status Server::disableSupplicant(bool* success) {
-  *success = supplicant_manager_->StopSupplicant();
-  return Status::ok();
-}
-
 Status Server::GetClientInterfaces(vector<sp<IBinder>>* out_client_interfaces) {
   vector<sp<android::IBinder>> client_interfaces_binder;
   for (auto& it : client_interfaces_) {
diff --git a/server.h b/server.h
index ded3518..cdce6b2 100644
--- a/server.h
+++ b/server.h
@@ -23,7 +23,6 @@
 
 #include <android-base/macros.h>
 #include <wifi_system/interface_tool.h>
-#include <wifi_system/supplicant_manager.h>
 
 #include "android/net/wifi/BnWificond.h"
 #include "android/net/wifi/IApInterface.h"
@@ -45,8 +44,6 @@
 class Server : public android::net::wifi::BnWificond {
  public:
   Server(std::unique_ptr<wifi_system::InterfaceTool> if_tool,
-         std::unique_ptr<wifi_system::SupplicantManager> supplicant_man,
-         std::unique_ptr<wifi_system::HostapdManager> hostapd_man,
          NetlinkUtils* netlink_utils,
          ScanUtils* scan_utils);
   ~Server() override = default;
@@ -86,8 +83,6 @@
       bool* out_success) override;
 
   android::binder::Status tearDownInterfaces() override;
-  android::binder::Status enableSupplicant(bool* success) override;
-  android::binder::Status disableSupplicant(bool* success) override;
 
   android::binder::Status GetClientInterfaces(
       std::vector<android::sp<android::IBinder>>* out_client_ifs) override;
@@ -116,8 +111,6 @@
   void MarkDownAllInterfaces();
 
   const std::unique_ptr<wifi_system::InterfaceTool> if_tool_;
-  const std::unique_ptr<wifi_system::SupplicantManager> supplicant_manager_;
-  const std::unique_ptr<wifi_system::HostapdManager> hostapd_manager_;
   NetlinkUtils* const netlink_utils_;
   ScanUtils* const scan_utils_;
 
diff --git a/tests/ap_interface_impl_unittest.cpp b/tests/ap_interface_impl_unittest.cpp
index bcd885d..0f1bf28 100644
--- a/tests/ap_interface_impl_unittest.cpp
+++ b/tests/ap_interface_impl_unittest.cpp
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <memory>
 #include <vector>
 
+#include <linux/if_ether.h>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <wifi_system_test/mock_hostapd_manager.h>
 #include <wifi_system_test/mock_interface_tool.h>
 
 #include "wificond/tests/mock_ap_interface_event_callback.h"
@@ -28,9 +30,8 @@
 
 #include "wificond/ap_interface_impl.h"
 
-using android::wifi_system::HostapdManager;
-using android::wifi_system::MockHostapdManager;
 using android::wifi_system::MockInterfaceTool;
+using std::array;
 using std::placeholders::_1;
 using std::placeholders::_2;
 using std::unique_ptr;
@@ -48,7 +49,7 @@
 
 const char kTestInterfaceName[] = "testwifi0";
 const uint32_t kTestInterfaceIndex = 42;
-const uint8_t kFakeMacAddress[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const array<uint8_t, ETH_ALEN> kFakeMacAddress = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
 
 void CaptureStationEventHandler(
     OnStationEventHandler* out_handler,
@@ -68,8 +69,6 @@
  protected:
   unique_ptr<NiceMock<MockInterfaceTool>> if_tool_{
       new NiceMock<MockInterfaceTool>};
-  unique_ptr<NiceMock<MockHostapdManager>> hostapd_manager_{
-      new NiceMock<MockHostapdManager>};
   unique_ptr<NiceMock<MockNetlinkManager>> netlink_manager_{
       new NiceMock<MockNetlinkManager>()};
   unique_ptr<NiceMock<MockNetlinkUtils>> netlink_utils_{
@@ -82,43 +81,12 @@
         kTestInterfaceName,
         kTestInterfaceIndex,
         netlink_utils_.get(),
-        if_tool_.get(),
-        hostapd_manager_.get()));
+        if_tool_.get()));
   }
 };  // class ApInterfaceImplTest
 
 }  // namespace
 
-TEST_F(ApInterfaceImplTest, ShouldReportStartFailure) {
-  EXPECT_CALL(*hostapd_manager_, StartHostapd())
-      .WillOnce(Return(false));
-  EXPECT_FALSE(ap_interface_->StartHostapd());
-}
-
-TEST_F(ApInterfaceImplTest, ShouldReportStartSuccess) {
-  EXPECT_CALL(*hostapd_manager_, StartHostapd())
-      .WillOnce(Return(true));
-  EXPECT_TRUE(ap_interface_->StartHostapd());
-}
-
-TEST_F(ApInterfaceImplTest, ShouldReportStopFailure) {
-  EXPECT_CALL(*hostapd_manager_, StopHostapd())
-      .WillOnce(Return(false));
-  EXPECT_FALSE(ap_interface_->StopHostapd());
-}
-
-TEST_F(ApInterfaceImplTest, ShouldReportStopSuccess) {
-  EXPECT_CALL(*hostapd_manager_, StopHostapd())
-      .WillOnce(Return(true));
-  EXPECT_CALL(*if_tool_, SetUpState(StrEq(kTestInterfaceName), false))
-      .WillOnce(Return(true));
-  EXPECT_CALL(*netlink_utils_, SetInterfaceMode(
-      kTestInterfaceIndex,
-      NetlinkUtils::STATION_MODE)).WillOnce(Return(true));
-  EXPECT_TRUE(ap_interface_->StopHostapd());
-  testing::Mock::VerifyAndClearExpectations(if_tool_.get());
-}
-
 TEST_F(ApInterfaceImplTest, CanGetNumberOfAssociatedStations) {
   OnStationEventHandler handler;
   EXPECT_CALL(*netlink_utils_,
@@ -129,11 +97,9 @@
         kTestInterfaceName,
         kTestInterfaceIndex,
         netlink_utils_.get(),
-        if_tool_.get(),
-        hostapd_manager_.get()));
+        if_tool_.get()));
 
-  vector<uint8_t> fake_mac_address(kFakeMacAddress,
-                                   kFakeMacAddress + sizeof(kFakeMacAddress));
+  array<uint8_t, ETH_ALEN> fake_mac_address = kFakeMacAddress;
   EXPECT_EQ(0, ap_interface_->GetNumberOfAssociatedStations());
   handler(NEW_STATION, fake_mac_address);
   EXPECT_EQ(1, ap_interface_->GetNumberOfAssociatedStations());
@@ -149,17 +115,15 @@
       .WillOnce(Invoke(bind(CaptureStationEventHandler, &handler, _1, _2)));
   ap_interface_.reset(new ApInterfaceImpl(
       kTestInterfaceName, kTestInterfaceIndex, netlink_utils_.get(),
-      if_tool_.get(), hostapd_manager_.get()));
+      if_tool_.get()));
 
-  EXPECT_CALL(*hostapd_manager_, StartHostapd()).WillOnce(Return(true));
   auto binder = ap_interface_->GetBinder();
   sp<MockApInterfaceEventCallback> callback(new MockApInterfaceEventCallback());
   bool out_success = false;
-  EXPECT_TRUE(binder->startHostapd(callback, &out_success).isOk());
+  EXPECT_TRUE(binder->registerCallback(callback, &out_success).isOk());
   EXPECT_TRUE(out_success);
 
-  vector<uint8_t> fake_mac_address(kFakeMacAddress,
-                                   kFakeMacAddress + sizeof(kFakeMacAddress));
+  array<uint8_t, ETH_ALEN> fake_mac_address = kFakeMacAddress;
   EXPECT_CALL(*callback, onNumAssociatedStationsChanged(1));
   handler(NEW_STATION, fake_mac_address);
   EXPECT_CALL(*callback, onNumAssociatedStationsChanged(2));
@@ -174,13 +138,12 @@
       .WillOnce(Invoke(bind(CaptureChannelSwitchEventHandler, &handler, _1, _2)));
   ap_interface_.reset(new ApInterfaceImpl(
       kTestInterfaceName, kTestInterfaceIndex, netlink_utils_.get(),
-      if_tool_.get(), hostapd_manager_.get()));
+      if_tool_.get()));
 
-  EXPECT_CALL(*hostapd_manager_, StartHostapd()).WillOnce(Return(true));
   auto binder = ap_interface_->GetBinder();
   sp<MockApInterfaceEventCallback> callback(new MockApInterfaceEventCallback());
   bool out_success = false;
-  EXPECT_TRUE(binder->startHostapd(callback, &out_success).isOk());
+  EXPECT_TRUE(binder->registerCallback(callback, &out_success).isOk());
   EXPECT_TRUE(out_success);
 
   const uint32_t kTestChannelFrequency = 2437;
diff --git a/tests/client_interface_impl_unittest.cpp b/tests/client_interface_impl_unittest.cpp
index da61ce6..5929139 100644
--- a/tests/client_interface_impl_unittest.cpp
+++ b/tests/client_interface_impl_unittest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <memory>
 #include <vector>
 
@@ -22,6 +23,7 @@
 #include <wifi_system_test/mock_interface_tool.h>
 
 #include "wificond/client_interface_impl.h"
+#include "wificond/tests/mock_i_send_mgmt_frame_event.h"
 #include "wificond/tests/mock_netlink_manager.h"
 #include "wificond/tests/mock_netlink_utils.h"
 #include "wificond/tests/mock_scan_utils.h"
@@ -29,8 +31,10 @@
 using android::wifi_system::MockInterfaceTool;
 using std::unique_ptr;
 using std::vector;
+using testing::Mock;
 using testing::NiceMock;
 using testing::Return;
+using testing::StrictMock;
 using testing::_;
 
 namespace android {
@@ -40,21 +44,44 @@
 const uint32_t kTestWiphyIndex = 2;
 const char kTestInterfaceName[] = "testwifi0";
 const uint32_t kTestInterfaceIndex = 42;
-const size_t kMacAddrLenBytes = ETH_ALEN;
+const uint64_t kCookie = 42;
+const int32_t kAutoMcs = -1;
+const int32_t kMcs = 5;
+const uint8_t kTestFrame[] = {0x00, 0x01, 0x02, 0x03};
 
 class ClientInterfaceImplTest : public ::testing::Test {
  protected:
 
   void SetUp() override {
+    SetUp(WiphyFeatures());
+  }
+
+  /**
+   * call SetUp(WiphyFeatures wiphy_features) in your test function if
+   * you would like to change WiphyFeatures.
+   */
+  void SetUp(WiphyFeatures wiphy_features) {
     EXPECT_CALL(*netlink_utils_,
                 SubscribeMlmeEvent(kTestInterfaceIndex, _));
     EXPECT_CALL(*netlink_utils_,
-                GetWiphyInfo(kTestWiphyIndex, _, _, _));
+                GetWiphyInfo(kTestWiphyIndex, _, _, _))
+      .WillOnce([wiphy_features](uint32_t wiphy_index, BandInfo* out_band_info,
+          ScanCapabilities* out_scan_capabilities,
+          WiphyFeatures* out_wiphy_features) {
+        *out_wiphy_features = wiphy_features;
+        return true;
+      });
+    EXPECT_CALL(*netlink_utils_,
+                SubscribeFrameTxStatusEvent(kTestInterfaceIndex, _))
+        .WillOnce([this](uint32_t interface_index,
+            OnFrameTxStatusEventHandler handler) {
+          frame_tx_status_event_handler_ = handler;
+        });
     client_interface_.reset(new ClientInterfaceImpl{
         kTestWiphyIndex,
         kTestInterfaceName,
         kTestInterfaceIndex,
-        vector<uint8_t>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+        std::array<uint8_t, ETH_ALEN>{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
         if_tool_.get(),
         netlink_utils_.get(),
         scan_utils_.get()});
@@ -63,6 +90,8 @@
   void TearDown() override {
     EXPECT_CALL(*netlink_utils_,
                 UnsubscribeMlmeEvent(kTestInterfaceIndex));
+    EXPECT_CALL(*netlink_utils_,
+                UnsubscribeFrameTxStatusEvent(kTestInterfaceIndex));
   }
 
   unique_ptr<NiceMock<MockInterfaceTool>> if_tool_{
@@ -74,28 +103,24 @@
   unique_ptr<NiceMock<MockScanUtils>> scan_utils_{
       new NiceMock<MockScanUtils>(netlink_manager_.get())};
   unique_ptr<ClientInterfaceImpl> client_interface_;
+  OnFrameTxStatusEventHandler frame_tx_status_event_handler_;
+  sp<StrictMock<MockISendMgmtFrameEvent>> send_mgmt_frame_event_{
+      new StrictMock<MockISendMgmtFrameEvent>()};
 };  // class ClientInterfaceImplTest
 
 }  // namespace
 
-TEST_F(ClientInterfaceImplTest, SetMacAddressFailsOnInvalidInput) {
-  EXPECT_FALSE(client_interface_->SetMacAddress(
-      std::vector<uint8_t>(kMacAddrLenBytes - 1)));
-  EXPECT_FALSE(client_interface_->SetMacAddress(
-      std::vector<uint8_t>(kMacAddrLenBytes + 1)));
-}
-
 TEST_F(ClientInterfaceImplTest, SetMacAddressFailsOnInterfaceDownFailure) {
   EXPECT_CALL(*if_tool_, SetWifiUpState(false)).WillOnce(Return(false));
   EXPECT_FALSE(
-      client_interface_->SetMacAddress(std::vector<uint8_t>(kMacAddrLenBytes)));
+      client_interface_->SetMacAddress(std::array<uint8_t, ETH_ALEN>()));
 }
 
 TEST_F(ClientInterfaceImplTest, SetMacAddressFailsOnAddressChangeFailure) {
   EXPECT_CALL(*if_tool_, SetWifiUpState(false)).WillOnce(Return(true));
   EXPECT_CALL(*if_tool_, SetMacAddress(_, _)).WillOnce(Return(false));
   EXPECT_FALSE(
-      client_interface_->SetMacAddress(std::vector<uint8_t>(kMacAddrLenBytes)));
+      client_interface_->SetMacAddress(std::array<uint8_t, ETH_ALEN>()));
 }
 
 TEST_F(ClientInterfaceImplTest, SetMacAddressFailsOnInterfaceUpFailure) {
@@ -103,7 +128,7 @@
   EXPECT_CALL(*if_tool_, SetMacAddress(_, _)).WillOnce(Return(true));
   EXPECT_CALL(*if_tool_, SetWifiUpState(true)).WillOnce(Return(false));
   EXPECT_FALSE(
-      client_interface_->SetMacAddress(std::vector<uint8_t>(kMacAddrLenBytes)));
+      client_interface_->SetMacAddress(std::array<uint8_t, ETH_ALEN>()));
 }
 
 TEST_F(ClientInterfaceImplTest, SetMacAddressReturnsTrueOnSuccess) {
@@ -111,17 +136,274 @@
   EXPECT_CALL(*if_tool_, SetMacAddress(_, _)).WillOnce(Return(true));
   EXPECT_CALL(*if_tool_, SetWifiUpState(true)).WillOnce(Return(true));
   EXPECT_TRUE(
-      client_interface_->SetMacAddress(std::vector<uint8_t>(kMacAddrLenBytes)));
+      client_interface_->SetMacAddress(std::array<uint8_t, ETH_ALEN>()));
 }
 
 TEST_F(ClientInterfaceImplTest, SetMacAddressPassesCorrectAddressToIfTool) {
   EXPECT_CALL(*if_tool_, SetWifiUpState(false)).WillOnce(Return(true));
   EXPECT_CALL(*if_tool_, SetMacAddress(_,
-      std::array<uint8_t, kMacAddrLenBytes>{{1, 2, 3, 4, 5, 6}}))
+      std::array<uint8_t, ETH_ALEN>{{1, 2, 3, 4, 5, 6}}))
     .WillOnce(Return(true));
   EXPECT_CALL(*if_tool_, SetWifiUpState(true)).WillOnce(Return(true));
   EXPECT_TRUE(client_interface_->SetMacAddress(
-      std::vector<uint8_t>{1, 2, 3, 4, 5, 6}));
+      std::array<uint8_t, ETH_ALEN>{{1, 2, 3, 4, 5, 6}}));
+}
+
+/**
+ * If the device does not support sending mgmt frame at specified MCS rate,
+ * and the caller specifies a MCS < 0, the call should still succeed (and the
+ * driver will determine the MCS rate automatically).
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsUnsupportedAutoSelectMcs) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(kCookie, true);
+}
+
+/**
+ * If the device does not support sending mgmt frame at specified MCS rate,
+ * and the caller specifies a MCS >= 0, the call should fail.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsUnsupportedCallerSpecifiedMcs) {
+  EXPECT_CALL(*send_mgmt_frame_event_,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kMcs);
+}
+
+/**
+ * If the device does support sending mgmt frame at specified MCS rate and the
+ * user specifies a valid MCS rate, the call should succeed.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameMcsSupported) {
+  WiphyFeatures wiphy_features;
+  wiphy_features.supports_tx_mgmt_frame_mcs = true;
+  SetUp(wiphy_features);
+
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kMcs);
+  frame_tx_status_event_handler_(kCookie, true);
+}
+
+/**
+ * Transmitted frame was not ACKed.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameNotAcked) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(kCookie, false);
+}
+
+/**
+ * Transmission failed due to unknown NL80211 error.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameUnknownError) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+        vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)), kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      return false;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_UNKNOWN));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+}
+
+/**
+ * Received cookie was different than expected; No callback should be triggered.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameWrongCookie) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(
+      kCookie + 1, // wrong cookie
+      false);
+
+  // StrictMock<MockISendMgmtFrameEvent> will fail if any unexpected method is
+  // called, guaranteeing no interaction with the callback.
+}
+
+/**
+ * frame_tx_status_event_handler_ triggered even though no transmission is in
+ * progress. No callback should be triggered.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameNoTxCallbackTriggered) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(kCookie, false);
+
+  // transmission has finished here.
+
+  // Now send another Tx status event.
+  frame_tx_status_event_handler_(kCookie + 1, false);
+  // StrictMock<MockISendMgmtFrameEvent> will fail if any unexpected method is
+  // called, guaranteeing no more interaction with the callback.
+}
+
+/**
+ * Second transmission was started even though no Tx Status event was received
+ * for the first transmission. Should discard first transmission, and second
+ * transmission should work normally.
+ *
+ * Since timeout of this SendMgmtFrame() is managed by framework, and framework
+ * does not notify wificond when the call times out, wificond should still work
+ * when a second call is made, even though it seems as though the first call is
+ * still incomplete.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameSecondTxWhileFirstTxIncomplete) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    })
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie + 1;
+      return true;
+    });
+
+  // first transmission; no tx status
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+
+  sp<StrictMock<MockISendMgmtFrameEvent>> send_mgmt_frame_event2{
+      new StrictMock<MockISendMgmtFrameEvent>()};
+
+  EXPECT_CALL(*send_mgmt_frame_event2,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
+
+  // second transmission; yes tx status
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event2, kAutoMcs);
+  frame_tx_status_event_handler_(kCookie + 1, false);
+
+  // now trigger tx status for first call; nothing should happen (implicitly
+  // verified by StrictMock).
+  frame_tx_status_event_handler_(kCookie, false);
+}
+
+/**
+ * Tests that internal state is reset correctly between calls by performing
+ * two transmissions in sequence.
+ */
+TEST_F(ClientInterfaceImplTest, SendMgmtFrameInternalStateResetBetweenCalls) {
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([](uint32_t interface_index, const vector<uint8_t>& frame,
+        int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = kCookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_, OnAck(_));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(kCookie, true);
+
+  Mock::VerifyAndClearExpectations(netlink_utils_.get());
+  Mock::VerifyAndClearExpectations(send_mgmt_frame_event_.get());
+
+  uint64_t new_cookie = kCookie + 1;
+
+  EXPECT_CALL(*netlink_utils_,
+      SendMgmtFrame(kTestInterfaceIndex,
+          vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+          kAutoMcs, _))
+    .WillOnce([new_cookie](uint32_t interface_index,
+        const vector<uint8_t>& frame, int32_t mcs, uint64_t* out_cookie) {
+      *out_cookie = new_cookie;
+      return true;
+    });
+
+  EXPECT_CALL(*send_mgmt_frame_event_,
+      OnFailure(send_mgmt_frame_event_->SEND_MGMT_FRAME_ERROR_NO_ACK));
+
+  client_interface_->SendMgmtFrame(
+      vector<uint8_t>(std::begin(kTestFrame), std::end(kTestFrame)),
+      send_mgmt_frame_event_, kAutoMcs);
+  frame_tx_status_event_handler_(new_cookie, false);
 }
 
 }  // namespace wificond
diff --git a/tests/integration/ap_interface_test.cpp b/tests/integration/ap_interface_test.cpp
index d562b61..3af92f7 100644
--- a/tests/integration/ap_interface_test.cpp
+++ b/tests/integration/ap_interface_test.cpp
@@ -29,8 +29,6 @@
 using android::net::wifi::IWificond;
 using android::wifi_system::InterfaceTool;
 using android::wificond::MockApInterfaceEventCallback;
-using android::wificond::tests::integration::HostapdIsDead;
-using android::wificond::tests::integration::HostapdIsRunning;
 using android::wificond::tests::integration::ScopedDevModeWificond;
 using android::wificond::tests::integration::WaitForTrue;
 using std::string;
@@ -40,8 +38,6 @@
 namespace wificond {
 namespace {
 const char kInterfaceName[] = "wlan0";
-constexpr int kHostapdStartupTimeoutSeconds = 3;
-constexpr int kHostapdDeathTimeoutSeconds = 3;
 }  // namespace
 
 TEST(ApInterfaceTest, CanCreateApInterfaces) {
@@ -79,59 +75,5 @@
   // Teardown everything at the end of the test.
   EXPECT_TRUE(service->tearDownInterfaces().isOk());
 }
-
-// TODO: b/30311493 this test fails because hostapd fails to set the driver
-//       channel every other time.
-TEST(ApInterfaceTest, CanStartStopHostapd) {
-  ScopedDevModeWificond dev_mode;
-  sp<IWificond> service = dev_mode.EnterDevModeOrDie();
-  sp<IApInterface> ap_interface;
-  EXPECT_TRUE(service->createApInterface(kInterfaceName, &ap_interface).isOk());
-  ASSERT_NE(nullptr, ap_interface.get());
-
-  // Interface should start out down.
-  string if_name;
-  EXPECT_TRUE(ap_interface->getInterfaceName(&if_name).isOk());
-  EXPECT_TRUE(!if_name.empty());
-  InterfaceTool if_tool;
-  EXPECT_FALSE(if_tool.GetUpState(if_name.c_str()));
-
-  sp<MockApInterfaceEventCallback> ap_interface_event_callback(
-      new MockApInterfaceEventCallback());
-
-  for (int iteration = 0; iteration < 4; iteration++) {
-    bool hostapd_started = false;
-    EXPECT_TRUE(
-        ap_interface
-            ->startHostapd(ap_interface_event_callback, &hostapd_started)
-            .isOk());
-    EXPECT_TRUE(hostapd_started);
-
-    EXPECT_TRUE(WaitForTrue(HostapdIsRunning, kHostapdStartupTimeoutSeconds))
-        << "Failed on iteration " << iteration;
-
-    // There are two reasons to do this:
-    //   1) We look for hostapd so quickly that we miss when it dies on startup
-    //   2) If we don't give hostapd enough time to get fully up, killing it
-    //      can leave the driver in a poor state.
-    // The latter points to an obvious race, where we cannot fully clean up the
-    // driver on quick transitions.
-    auto InterfaceIsUp = [&if_tool, &if_name] () {
-      return if_tool.GetUpState(if_name.c_str());
-    };
-    EXPECT_TRUE(WaitForTrue(InterfaceIsUp, kHostapdStartupTimeoutSeconds))
-        << "Failed on iteration " << iteration;
-    EXPECT_TRUE(HostapdIsRunning()) << "Failed on iteration " << iteration;
-
-    bool hostapd_stopped = false;
-    EXPECT_TRUE(ap_interface->stopHostapd(&hostapd_stopped).isOk());
-    EXPECT_TRUE(hostapd_stopped);
-    EXPECT_FALSE(if_tool.GetUpState(if_name.c_str()));
-
-
-    EXPECT_TRUE(WaitForTrue(HostapdIsDead, kHostapdDeathTimeoutSeconds))
-        << "Failed on iteration " << iteration;
-  }
-}
 }  // namespace wificond
 }  // namespace android
diff --git a/tests/integration/client_interface_test.cpp b/tests/integration/client_interface_test.cpp
index e25222b..37b9dba 100644
--- a/tests/integration/client_interface_test.cpp
+++ b/tests/integration/client_interface_test.cpp
@@ -29,9 +29,6 @@
 using android::net::wifi::IWificond;
 using android::wifi_system::InterfaceTool;
 using android::wificond::tests::integration::ScopedDevModeWificond;
-using android::wificond::tests::integration::SupplicantIsDead;
-using android::wificond::tests::integration::SupplicantIsRunning;
-using android::wificond::tests::integration::WaitForTrue;
 using std::string;
 using std::vector;
 
diff --git a/tests/integration/service_test.cpp b/tests/integration/service_test.cpp
deleted file mode 100644
index 1711339..0000000
--- a/tests/integration/service_test.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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 <utils/StrongPointer.h>
-
-#include "android/net/wifi/IClientInterface.h"
-#include "android/net/wifi/IWificond.h"
-#include "wificond/tests/integration/process_utils.h"
-#include "wificond/tests/shell_utils.h"
-
-using android::net::wifi::IClientInterface;
-using android::net::wifi::IWificond;
-using android::sp;
-using android::wificond::tests::integration::RunShellCommand;
-using android::wificond::tests::integration::ScopedDevModeWificond;
-using android::wificond::tests::integration::SupplicantIsDead;
-using android::wificond::tests::integration::SupplicantIsRunning;
-using android::wificond::tests::integration::WaitForTrue;
-using android::wificond::tests::integration::WificondIsDead;
-
-namespace android {
-namespace wificond {
-namespace {
-
-constexpr int kTimeoutSeconds = 3;
-}  // namespace
-
-TEST(ServiceTest, ShouldTearDownSystemOnStartup) {
-  // Simulate doing normal connectivity things by startup supplicant.
-  ScopedDevModeWificond dev_mode;
-  sp<IWificond> service = dev_mode.EnterDevModeOrDie();
-
-  bool supplicant_started = false;
-  EXPECT_TRUE(service->enableSupplicant(&supplicant_started).isOk());
-  EXPECT_TRUE(supplicant_started);
-
-  EXPECT_TRUE(WaitForTrue(SupplicantIsRunning, kTimeoutSeconds));
-
-  // Kill wificond abruptly.  It should not clean up on the way out.
-  RunShellCommand("stop wificond");
-  EXPECT_TRUE(WaitForTrue(WificondIsDead, kTimeoutSeconds));
-
-  // Supplicant should still be up.
-  EXPECT_TRUE(SupplicantIsRunning());
-
-  // Restart wificond, which should kill supplicant on startup.
-  service = dev_mode.EnterDevModeOrDie();
-  EXPECT_TRUE(WaitForTrue(SupplicantIsDead, kTimeoutSeconds));
-}
-
-TEST(ServiceTest, CanStartStopSupplicant) {
-  ScopedDevModeWificond dev_mode;
-  sp<IWificond> service = dev_mode.EnterDevModeOrDie();
-
-  for (int iteration = 0; iteration < 4; iteration++) {
-    bool supplicant_started = false;
-    EXPECT_TRUE(service->enableSupplicant(&supplicant_started).isOk());
-    EXPECT_TRUE(supplicant_started);
-
-    EXPECT_TRUE(WaitForTrue(SupplicantIsRunning,
-                            kTimeoutSeconds))
-        << "Failed on iteration " << iteration;
-
-    // We look for supplicant so quickly that we miss when it dies on startup
-    sleep(1);
-    EXPECT_TRUE(SupplicantIsRunning()) << "Failed on iteration " << iteration;
-
-    bool supplicant_stopped = false;
-    EXPECT_TRUE(
-        service->disableSupplicant(&supplicant_stopped).isOk());
-    EXPECT_TRUE(supplicant_stopped);
-
-    EXPECT_TRUE(WaitForTrue(SupplicantIsDead, kTimeoutSeconds))
-        << "Failed on iteration " << iteration;
-  }
-}
-
-}  // namespace wificond
-}  // namespace android
diff --git a/tests/mock_client_interface_impl.cpp b/tests/mock_client_interface_impl.cpp
index ba88f1c..8476cff 100644
--- a/tests/mock_client_interface_impl.cpp
+++ b/tests/mock_client_interface_impl.cpp
@@ -18,8 +18,9 @@
 
 #include <vector>
 
+#include <linux/if_ether.h>
+
 #include <wifi_system/interface_tool.h>
-#include <wifi_system/supplicant_manager.h>
 
 #include "wificond/net/netlink_utils.h"
 #include "wificond/scanning/scan_utils.h"
@@ -28,7 +29,7 @@
 namespace wificond {
 
 const char kTestInterfaceName[] = "testwifi0";
-const uint8_t kTestInterfaceMacAddress[] = {0x10, 0x20, 0xfe, 0xae, 0x2d, 0xc2};
+const std::array<uint8_t, ETH_ALEN> kTestInterfaceMacAddress = {0x10, 0x20, 0xfe, 0xae, 0x2d, 0xc2};
 const uint32_t kTestInterfaceIndex = 42;
 const uint32_t kTestWiphyIndex = 2;
 
@@ -40,9 +41,7 @@
         kTestWiphyIndex,
         kTestInterfaceName,
         kTestInterfaceIndex,
-        std::vector<uint8_t>(
-            kTestInterfaceMacAddress,
-            kTestInterfaceMacAddress + arraysize(kTestInterfaceMacAddress)),
+        std::array<uint8_t, ETH_ALEN>(kTestInterfaceMacAddress),
         interface_tool,
         netlink_utils,
         scan_utils) {}
diff --git a/tests/mock_i_send_mgmt_frame_event.h b/tests/mock_i_send_mgmt_frame_event.h
new file mode 100644
index 0000000..30b7da7
--- /dev/null
+++ b/tests/mock_i_send_mgmt_frame_event.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFICOND_TESTS_MOCK_I_SEND_MGMT_FRAME_EVENT_H_
+#define WIFICOND_TESTS_MOCK_I_SEND_MGMT_FRAME_EVENT_H_
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "android/net/wifi/ISendMgmtFrameEvent.h"
+
+namespace android {
+namespace wificond {
+
+class MockISendMgmtFrameEvent
+    : public ::android::net::wifi::ISendMgmtFrameEvent {
+ public:
+  virtual ~MockISendMgmtFrameEvent() override = default;
+
+  MOCK_METHOD0(onAsBinder, ::android::IBinder*());
+  MOCK_METHOD1(OnAck, ::android::binder::Status(int elapsed_time_ms));
+  MOCK_METHOD1(OnFailure, ::android::binder::Status(int reason));
+};
+
+}
+}
+
+#endif // WIFICOND_TESTS_MOCK_I_SEND_MGMT_FRAME_EVENT_H_
diff --git a/tests/mock_netlink_utils.h b/tests/mock_netlink_utils.h
index fd0868f..708a385 100644
--- a/tests/mock_netlink_utils.h
+++ b/tests/mock_netlink_utils.h
@@ -30,10 +30,13 @@
   ~MockNetlinkUtils() override = default;
 
   MOCK_METHOD1(GetWiphyIndex, bool(uint32_t* out_wiphy_index));
+  MOCK_METHOD2(GetWiphyIndex,
+               bool(uint32_t* out_wiphy_index, const std::string& iface_name));
   MOCK_METHOD1(UnsubscribeMlmeEvent, void(uint32_t interface_index));
   MOCK_METHOD1(UnsubscribeRegDomainChange, void(uint32_t wiphy_index));
   MOCK_METHOD1(UnsubscribeStationEvent, void(uint32_t interface_index));
   MOCK_METHOD1(UnsubscribeChannelSwitchEvent, void(uint32_t interface_index));
+  MOCK_METHOD1(UnsubscribeFrameTxStatusEvent, void(uint32_t interface_index));
   MOCK_METHOD1(GetProtocolFeatures, bool(uint32_t* features));
 
   MOCK_METHOD2(SetInterfaceMode,
@@ -50,6 +53,9 @@
   MOCK_METHOD2(SubscribeChannelSwitchEvent,
                void(uint32_t interface_index,
                     OnChannelSwitchEventHandler handler));
+  MOCK_METHOD2(SubscribeFrameTxStatusEvent,
+               void(uint32_t interface_index,
+                    OnFrameTxStatusEventHandler handler));
 
   MOCK_METHOD2(GetInterfaces,
                bool(uint32_t wiphy_index,
@@ -59,6 +65,11 @@
                     BandInfo* band_info,
                     ScanCapabilities* scan_capabilities,
                     WiphyFeatures* wiphy_features));
+  MOCK_METHOD4(SendMgmtFrame,
+               bool(uint32_t interface_index,
+                    const std::vector<uint8_t>& frame,
+                    int32_t mcs,
+                    uint64_t* out_cookie));
 
 };  // class MockNetlinkUtils
 
diff --git a/tests/mock_scan_utils.h b/tests/mock_scan_utils.h
index 9a8fd93..eb7e9c7 100644
--- a/tests/mock_scan_utils.h
+++ b/tests/mock_scan_utils.h
@@ -49,13 +49,12 @@
       const std::vector<uint32_t>& freqs,
       int* error_code));
 
-  MOCK_METHOD10(StartScheduledScan, bool(
+  MOCK_METHOD9(StartScheduledScan, bool(
       uint32_t interface_index,
       const SchedScanIntervalSetting& interval_setting,
       int32_t rssi_threshold_2g,
       int32_t rssi_threshold_5g,
-      bool request_random_mac,
-      bool request_low_power,
+      const SchedScanReqFlags& req_flags,
       const std::vector<std::vector<uint8_t>>& scan_ssids,
       const std::vector<std::vector<uint8_t>>& match_ssids,
       const std::vector<uint32_t>& freqs,
diff --git a/tests/netlink_utils_unittest.cpp b/tests/netlink_utils_unittest.cpp
index 4e7fd56..34f5c21 100644
--- a/tests/netlink_utils_unittest.cpp
+++ b/tests/netlink_utils_unittest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <memory>
 #include <string>
 #include <vector>
@@ -58,19 +59,23 @@
 constexpr uint32_t kFakeProtocolFeatures = 0x02;
 constexpr uint16_t kFakeWiphyIndex = 8;
 constexpr uint16_t kFakeWiphyIndex1 = 10;
+constexpr uint64_t kFakeCookie = 42;
 constexpr int kFakeErrorCode = EIO;
+constexpr int32_t kFakeMcs = 5;
 constexpr bool kFakeSupportsRandomMacOneshotScan = true;
 constexpr bool kFakeSupportsRandomMacSchedScan = false;
 const char kFakeInterfaceName[] = "testif0";
 const char kFakeCountryCode[] = "US";
 const uint32_t kFakeInterfaceIndex = 34;
 const uint32_t kFakeInterfaceIndex1 = 36;
-const uint8_t kFakeInterfaceMacAddress[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
-const uint8_t kFakeInterfaceMacAddress1[] = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
+const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress1 = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
 const uint8_t kFakeExtFeaturesForLowSpanScan[] = {0x0, 0x0, 0x40};
 const uint8_t kFakeExtFeaturesForLowPowerScan[] = {0x0, 0x0, 0x80};
 const uint8_t kFakeExtFeaturesForHighAccuracy[] = {0x0, 0x0, 0x0, 0x1};
 const uint8_t kFakeExtFeaturesForAllScanType[] = {0x0, 0x0, 0xC0, 0x1};
+const uint8_t kFakeFrame[] = {0x00, 0x01, 0x02, 0x03};
+
 
 // Currently, control messages are only created by the kernel and sent to us.
 // Therefore NL80211Packet doesn't have corresponding constructor.
@@ -367,11 +372,8 @@
   NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex);
   new_interface.AddAttribute(if_index_attr);
   // Insert mac address attribute.
-  std::vector<uint8_t> if_mac_addr;
-  if_mac_addr.assign(
-      kFakeInterfaceMacAddress,
-      kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress));
-  NL80211Attr<vector<uint8_t>> if_mac_attr(NL80211_ATTR_MAC, if_mac_addr);
+  std::array<uint8_t, ETH_ALEN> if_mac_addr = kFakeInterfaceMacAddress;
+  NL80211Attr<std::array<uint8_t, ETH_ALEN>> if_mac_attr(NL80211_ATTR_MAC, if_mac_addr);
   new_interface.AddAttribute(if_mac_attr);
 
   // Mock a valid response from kernel.
@@ -409,12 +411,9 @@
       NL80211_ATTR_IFNAME, string(kFakeInterfaceName)));
   expected_interface.AddAttribute(NL80211Attr<uint32_t>(
       NL80211_ATTR_IFINDEX, kFakeInterfaceIndex));
-  std::vector<uint8_t> if_mac_addr;
-  if_mac_addr.assign(
-      kFakeInterfaceMacAddress,
-      kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress));
+  std::array<uint8_t, ETH_ALEN> if_mac_addr = kFakeInterfaceMacAddress;
   expected_interface.AddAttribute(
-      NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, if_mac_addr));
+      NL80211Attr<std::array<uint8_t, ETH_ALEN>>(NL80211_ATTR_MAC, if_mac_addr));
 
   // Kernel can send us the pseduo interface packet first
   vector<NL80211Packet> response = {psuedo_interface, expected_interface};
@@ -443,11 +442,9 @@
   new_interface.AddAttribute(
       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex));
   // Insert mac address attribute.
-  std::vector<uint8_t> if_mac_addr(
-      kFakeInterfaceMacAddress,
-      kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress));
+  std::array<uint8_t, ETH_ALEN> if_mac_addr = kFakeInterfaceMacAddress;
   new_interface.AddAttribute(
-      NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, if_mac_addr));
+      NL80211Attr<std::array<uint8_t, ETH_ALEN>>(NL80211_ATTR_MAC, if_mac_addr));
 
   // Create a new interface packet for p2p0.
   NL80211Packet new_interface_p2p0(
@@ -463,11 +460,9 @@
   new_interface_p2p0.AddAttribute(
       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex1));
   // Insert mac address attribute.
-  std::vector<uint8_t> if_mac_addr_p2p(
-      kFakeInterfaceMacAddress1,
-      kFakeInterfaceMacAddress1 + sizeof(kFakeInterfaceMacAddress1));
+  std::array<uint8_t, ETH_ALEN> if_mac_addr_p2p = kFakeInterfaceMacAddress1;
   new_interface_p2p0.AddAttribute(
-      NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, if_mac_addr_p2p));
+      NL80211Attr<std::array<uint8_t, ETH_ALEN>>(NL80211_ATTR_MAC, if_mac_addr_p2p));
 
   // Mock response from kernel, including 2 interfaces.
   vector<NL80211Packet> response = {new_interface_p2p0, new_interface};
@@ -835,7 +830,7 @@
   // Still use NL80211_CMD_GET_REG here.
   NL80211Packet get_country_code_response(
       netlink_manager_->GetFamilyId(),
-      NL80211_CMD_GET_PROTOCOL_FEATURES,
+      NL80211_CMD_GET_REG,
       netlink_manager_->GetSequenceNumber(),
       getpid());
   get_country_code_response.AddAttribute(
@@ -862,5 +857,40 @@
   EXPECT_FALSE(netlink_utils_->GetCountryCode(&country_code_ignored));
 }
 
+TEST_F(NetlinkUtilsTest, CanSendMgmtFrame) {
+  // There is no specification for the response packet id for
+  // NL80211_CMD_FRAME.
+  // Still use NL80211_CMD_FRAME here.
+  NL80211Packet send_mgmt_frame_response(
+      netlink_manager_->GetFamilyId(),
+      NL80211_CMD_FRAME,
+      netlink_manager_->GetSequenceNumber(),
+      getpid());
+  send_mgmt_frame_response.AddAttribute(
+      NL80211Attr<uint64_t>(NL80211_ATTR_COOKIE, kFakeCookie));
+  vector<NL80211Packet> response = {send_mgmt_frame_response};
+
+  EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _))
+    .WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+  uint64_t cookie;
+  EXPECT_TRUE(netlink_utils_->SendMgmtFrame(kFakeInterfaceIndex,
+      vector<uint8_t>(std::begin(kFakeFrame), std::end(kFakeFrame)),
+      kFakeMcs, &cookie));
+  EXPECT_EQ(kFakeCookie, cookie);
+}
+
+TEST_F(NetlinkUtilsTest, CanHandleSendMgmtFrameError) {
+  // Mock an error response from kernel.
+  vector<NL80211Packet> response = {CreateControlMessageError(kFakeErrorCode)};
+  EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
+      WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+  uint64_t cookie_ignored;
+  EXPECT_FALSE(netlink_utils_->SendMgmtFrame(kFakeInterfaceIndex,
+      vector<uint8_t>(std::begin(kFakeFrame), std::end(kFakeFrame)),
+      kFakeMcs, &cookie_ignored));
+}
+
 }  // namespace wificond
 }  // namespace android
diff --git a/tests/scan_result_unittest.cpp b/tests/scan_result_unittest.cpp
index 01dcfd7..facda6f 100644
--- a/tests/scan_result_unittest.cpp
+++ b/tests/scan_result_unittest.cpp
@@ -14,14 +14,18 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <vector>
 
+#include <linux/if_ether.h>
+
 #include <gtest/gtest.h>
 
 #include "wificond/scanning/scan_result.h"
 
 using ::com::android::server::wifi::wificond::NativeScanResult;
 using ::com::android::server::wifi::wificond::RadioChainInfo;
+using std::array;
 using std::vector;
 
 namespace android {
@@ -32,7 +36,7 @@
 
 const uint8_t kFakeSsid[] =
     {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
-const uint8_t kFakeBssid[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const array<uint8_t, ETH_ALEN> kFakeBssid = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
 const uint8_t kFakeIE[] = {0x05, 0x11, 0x32, 0x11};
 constexpr uint32_t kFakeFrequency = 5240;
 constexpr int32_t kFakeSignalMbm= -32;
@@ -49,7 +53,7 @@
 
 TEST_F(ScanResultTest, ParcelableTest) {
   std::vector<uint8_t> ssid(kFakeSsid, kFakeSsid + sizeof(kFakeSsid));
-  std::vector<uint8_t> bssid(kFakeBssid, kFakeBssid + sizeof(kFakeBssid));
+  array<uint8_t, ETH_ALEN> bssid = kFakeBssid;
   std::vector<uint8_t> ie(kFakeIE, kFakeIE + sizeof(kFakeIE));
   std::vector<RadioChainInfo> radio_chain_infos;
   radio_chain_infos.emplace_back(
diff --git a/tests/scan_utils_unittest.cpp b/tests/scan_utils_unittest.cpp
index 17f000b..f8ec523 100644
--- a/tests/scan_utils_unittest.cpp
+++ b/tests/scan_utils_unittest.cpp
@@ -56,6 +56,7 @@
 constexpr int32_t kFake5gRssiThreshold = -77;
 constexpr bool kFakeUseRandomMAC = true;
 constexpr bool kFakeRequestLowPower = true;
+constexpr bool kFakeRequestSchedScanRelativeRssi = true;
 constexpr int kFakeScanType = IWifiScannerImpl::SCAN_TYPE_LOW_SPAN;
 
 // Currently, control messages are only created by the kernel and sent to us.
@@ -151,7 +152,6 @@
           DoesNL80211PacketMatchCommand(NL80211_CMD_TRIGGER_SCAN), _)).
               WillOnce(Invoke(bind(
                   AppendMessageAndReturn, response, true, _1, _2)));
-
   int errno_ignored;
   EXPECT_TRUE(scan_utils_.Scan(kFakeInterfaceIndex, kFakeUseRandomMAC,
                                kFakeScanType, {}, {}, &errno_ignored));
@@ -273,12 +273,16 @@
            DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)).
               WillOnce(Invoke(bind(
                   AppendMessageAndReturn, response, true, _1, _2)));
+
+  const SchedScanReqFlags req_flags = {
+    kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
+  };
   int errno_ignored;
   EXPECT_TRUE(scan_utils_.StartScheduledScan(
       kFakeInterfaceIndex,
       SchedScanIntervalSetting(),
-      kFake2gRssiThreshold, kFake5gRssiThreshold,
-      kFakeUseRandomMAC, kFakeRequestLowPower, {}, {}, {}, &errno_ignored));
+      kFake2gRssiThreshold, kFake5gRssiThreshold, req_flags, {}, {}, {},
+      &errno_ignored));
   // TODO(b/34231420): Add validation of requested scan ssids, threshold,
   // and frequencies.
 }
@@ -291,12 +295,15 @@
            DoesNL80211PacketMatchCommand(NL80211_CMD_START_SCHED_SCAN), _)).
               WillOnce(Invoke(bind(
                   AppendMessageAndReturn, response, true, _1, _2)));
+  const SchedScanReqFlags req_flags = {
+    kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
+  };
   int error_code;
   EXPECT_FALSE(scan_utils_.StartScheduledScan(
       kFakeInterfaceIndex,
       SchedScanIntervalSetting(),
       kFake2gRssiThreshold, kFake5gRssiThreshold,
-      kFakeUseRandomMAC, kFakeRequestLowPower, {}, {}, {}, &error_code));
+      req_flags, {}, {}, {}, &error_code));
   EXPECT_EQ(kFakeErrorCode, error_code);
 }
 
@@ -311,11 +318,14 @@
                    NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_LOW_POWER)),
            _));
   int errno_ignored;
+  const SchedScanReqFlags req_flags = {
+    false, true, false
+  };
   scan_utils_.StartScheduledScan(
       kFakeInterfaceIndex,
       SchedScanIntervalSetting(),
       kFake2gRssiThreshold, kFake5gRssiThreshold,
-      false, true, {}, {}, {}, &errno_ignored);
+      req_flags, {}, {}, {}, &errno_ignored);
 }
 
 TEST_F(ScanUtilsTest, CanSpecifyScanPlansForSchedScanRequest) {
@@ -332,12 +342,14 @@
   SchedScanIntervalSetting interval_setting{
       {{kFakeScheduledScanIntervalMs, 10 /* repeated times */}},
       kFakeScheduledScanIntervalMs * 3 /* interval for infinite scans */};
-
+  const SchedScanReqFlags req_flags = {
+    kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
+  };
   scan_utils_.StartScheduledScan(
       kFakeInterfaceIndex,
       interval_setting,
       kFake2gRssiThreshold, kFake5gRssiThreshold,
-      kFakeUseRandomMAC, kFakeRequestLowPower, {}, {}, {}, &errno_ignored);
+      req_flags, {}, {}, {}, &errno_ignored);
 }
 
 TEST_F(ScanUtilsTest, CanSpecifySingleIntervalForSchedScanRequest) {
@@ -352,12 +364,14 @@
            _));
   int errno_ignored;
   SchedScanIntervalSetting interval_setting{{}, kFakeScheduledScanIntervalMs};
-
+  const SchedScanReqFlags req_flags = {
+    kFakeUseRandomMAC, kFakeRequestLowPower, kFakeRequestSchedScanRelativeRssi
+  };
   scan_utils_.StartScheduledScan(
       kFakeInterfaceIndex,
       interval_setting,
       kFake2gRssiThreshold, kFake5gRssiThreshold,
-      kFakeUseRandomMAC, kFakeRequestLowPower, {}, {}, {}, &errno_ignored);
+      req_flags, {}, {}, {}, &errno_ignored);
 }
 
 TEST_F(ScanUtilsTest, CanPrioritizeLastSeenSinceBootNetlinkAttribute) {
diff --git a/tests/scanner_unittest.cpp b/tests/scanner_unittest.cpp
index 463ab83..39a591e 100644
--- a/tests/scanner_unittest.cpp
+++ b/tests/scanner_unittest.cpp
@@ -19,8 +19,6 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <wifi_system_test/mock_interface_tool.h>
-#include <wifi_system_test/mock_supplicant_manager.h>
-
 #include "android/net/wifi/IWifiScannerImpl.h"
 #include "wificond/scanning/offload/offload_scan_utils.h"
 #include "wificond/scanning/scanner_impl.h"
@@ -37,9 +35,11 @@
 using ::android::net::wifi::IWifiScannerImpl;
 using ::android::wifi_system::MockInterfaceTool;
 using ::com::android::server::wifi::wificond::SingleScanSettings;
+using ::com::android::server::wifi::wificond::PnoNetwork;
 using ::com::android::server::wifi::wificond::PnoSettings;
 using ::com::android::server::wifi::wificond::NativeScanResult;
 using android::hardware::wifi::offload::V1_0::ScanResult;
+using ::testing::Eq;
 using ::testing::Invoke;
 using ::testing::NiceMock;
 using ::testing::Return;
@@ -81,8 +81,7 @@
     const SchedScanIntervalSetting&  interval_setting,
     int32_t /* rssi_threshold_2g */,
     int32_t /* rssi_threshold_5g */,
-    bool /* request_random_mac */,
-    bool /* request_low_power_scan */,
+    const SchedScanReqFlags&  /* req_flags */,
     const  std::vector<std::vector<uint8_t>>& /* scan_ssids */,
     const std::vector<std::vector<uint8_t>>& /* match_ssids */,
     const  std::vector<uint32_t>& /* freqs */,
@@ -92,6 +91,21 @@
   return true;
 }
 
+bool CaptureSchedScanReqFlags(
+    uint32_t /* interface_index */,
+    const SchedScanIntervalSetting&  /* interval_setting */,
+    int32_t /* rssi_threshold_2g */,
+    int32_t /* rssi_threshold_5g */,
+    const SchedScanReqFlags& req_flags,
+    const  std::vector<std::vector<uint8_t>>& /* scan_ssids */,
+    const std::vector<std::vector<uint8_t>>& /* match_ssids */,
+    const  std::vector<uint32_t>& /* freqs */,
+    int* /* error_code */,
+    SchedScanReqFlags* out_req_flags) {
+  *out_req_flags = req_flags;
+  return true;
+}
+
 bool ReturnOffloadScanResults(
     std::vector<NativeScanResult>* native_scan_results_,
     const std::vector<ScanResult>& offload_scan_results) {
@@ -321,7 +335,7 @@
                            &scan_utils_, offload_service_utils_);
   EXPECT_CALL(
       scan_utils_,
-      StartScheduledScan(_, _, _, _, _, false, _, _, _, _)).
+      StartScheduledScan(_, _, _, _, _,  _, _, _, _)).
           WillOnce(Return(true));
   EXPECT_TRUE(scanner_impl.startPnoScan(PnoSettings(), &success).isOk());
   EXPECT_TRUE(success);
@@ -336,12 +350,16 @@
   ScannerImpl scanner_impl(kFakeInterfaceIndex, scan_capabilities_,
                            wiphy_features_, &client_interface_impl_,
                            &scan_utils_, offload_service_utils_);
+  SchedScanReqFlags req_flags = {};
   EXPECT_CALL(
       scan_utils_,
-      StartScheduledScan(_, _, _, _, _, true, _, _, _, _)).
-          WillOnce(Return(true));
+      StartScheduledScan(_, _, _, _, _, _, _, _, _)).
+          WillOnce(Invoke(bind(
+              CaptureSchedScanReqFlags,
+              _1, _2, _3, _4, _5, _6, _7, _8, _9, &req_flags)));
   EXPECT_TRUE(scanner_impl.startPnoScan(PnoSettings(), &success).isOk());
   EXPECT_TRUE(success);
+  EXPECT_TRUE(req_flags.request_low_power);
 }
 
 TEST_F(ScannerTest, TestStopPnoScanViaNetlink) {
@@ -392,7 +410,7 @@
   EXPECT_CALL(*offload_scan_manager_, startScan(_, _, _, _, _, _, _))
       .WillOnce(Return(false));
   EXPECT_CALL(*offload_scan_manager_, stopScan(_)).Times(0);
-  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _, _))
+  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _))
       .WillOnce(Return(true));
   EXPECT_CALL(scan_utils_, StopScheduledScan(_)).WillOnce(Return(true));
   EXPECT_TRUE(scanner_impl_->startPnoScan(PnoSettings(), &success).isOk());
@@ -416,7 +434,7 @@
                                       scan_capabilities_, wiphy_features_,
                                       &client_interface_impl_,
                                       &scan_utils_, offload_service_utils_));
-  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _, _))
+  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _))
       .WillOnce(Return(true));
   EXPECT_CALL(scan_utils_, StopScheduledScan(_)).WillOnce(Return(true));
   scanner_impl_->startPnoScan(PnoSettings(), &success);
@@ -476,7 +494,7 @@
                                       scan_capabilities_, wiphy_features_,
                                       &client_interface_impl_,
                                       &scan_utils_, offload_service_utils_));
-  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _, _))
+  EXPECT_CALL(scan_utils_, StartScheduledScan(_, _, _, _, _, _, _, _, _))
       .WillOnce(Return(true));
   EXPECT_CALL(scan_utils_, StopScheduledScan(_)).WillOnce(Return(true));
   EXPECT_TRUE(scanner_impl_->startPnoScan(PnoSettings(), &success).isOk());
@@ -511,10 +529,10 @@
   SchedScanIntervalSetting interval_setting;
   EXPECT_CALL(
       scan_utils_,
-      StartScheduledScan(_, _, _, _, _, _, _, _, _, _)).
+      StartScheduledScan(_, _, _, _, _, _, _, _, _)).
               WillOnce(Invoke(bind(
                   CaptureSchedScanIntervalSetting,
-                  _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, &interval_setting)));
+                  _1, _2, _3, _4, _5, _6, _7, _8, _9, &interval_setting)));
 
   bool success_ignored = 0;
   EXPECT_TRUE(scanner.startPnoScan(pno_settings, &success_ignored).isOk());
@@ -544,10 +562,10 @@
   SchedScanIntervalSetting interval_setting;
   EXPECT_CALL(
       scan_utils_,
-      StartScheduledScan(_, _, _, _, _, _, _, _, _, _)).
+      StartScheduledScan(_, _, _, _, _, _, _, _, _)).
               WillOnce(Invoke(bind(
                   CaptureSchedScanIntervalSetting,
-                  _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, &interval_setting)));
+                  _1, _2, _3, _4, _5, _6, _7, _8, _9, &interval_setting)));
 
   bool success_ignored = 0;
   EXPECT_TRUE(scanner.startPnoScan(pno_settings, &success_ignored).isOk());
@@ -556,5 +574,165 @@
   EXPECT_EQ(kFakeScanIntervalMs, interval_setting.final_interval_ms);
 }
 
+TEST_F(ScannerTest, TestGetScanResultsOnInvalidatedScannerImpl) {
+  vector<NativeScanResult> scan_results;
+  scanner_impl_.reset(new ScannerImpl(kFakeInterfaceIndex,
+                                      scan_capabilities_, wiphy_features_,
+                                      &client_interface_impl_,
+                                      &scan_utils_, offload_service_utils_));
+  scanner_impl_->Invalidate();
+  EXPECT_CALL(scan_utils_, GetScanResult(_, _))
+      .Times(0)
+      .WillOnce(Return(true));
+  EXPECT_TRUE(scanner_impl_->getScanResults(&scan_results).isOk());
+}
+
+// Verify that pno scanning starts with no errors given a non-empty frequency list.
+TEST_F(ScannerTest, TestStartPnoScanWithNonEmptyFrequencyList) {
+  bool success = false;
+  ScanCapabilities scan_capabilities_test_frequencies(
+      1 /* max_num_scan_ssids */,
+      1 /* max_num_sched_scan_ssids */,
+      1 /* max_match_sets */,
+      0,
+      kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier / 1000,
+      PnoSettings::kFastScanIterations);
+  EXPECT_CALL(*offload_service_utils_, IsOffloadScanSupported())
+        .Times(1)
+        .WillRepeatedly(Return(false));
+  ScannerImpl scanner_impl(kFakeInterfaceIndex, scan_capabilities_test_frequencies,
+                           wiphy_features_, &client_interface_impl_,
+                           &scan_utils_, offload_service_utils_);
+
+  PnoSettings pno_settings;
+  PnoNetwork network;
+  network.is_hidden_ = false;
+  network.frequencies_.push_back(2412);
+  pno_settings.pno_networks_.push_back(network);
+
+  std::vector<uint32_t> expected_freqs;
+  expected_freqs.push_back(2412);
+  EXPECT_CALL(
+      scan_utils_,
+      StartScheduledScan(_, _, _, _, _, _, _, Eq(expected_freqs), _)).
+          WillOnce(Return(true));
+  EXPECT_TRUE(scanner_impl.startPnoScan(pno_settings, &success).isOk());
+  EXPECT_TRUE(success);
+}
+
+// Verify that a unique set of frequencies is passed in for scanning when the input
+// contains duplicate frequencies.
+TEST_F(ScannerTest, TestStartPnoScanWithFrequencyListNoDuplicates) {
+  bool success = false;
+  ScanCapabilities scan_capabilities_test_frequencies(
+      1 /* max_num_scan_ssids */,
+      1 /* max_num_sched_scan_ssids */,
+      2 /* max_match_sets */,
+      0,
+      kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier / 1000,
+      PnoSettings::kFastScanIterations);
+  EXPECT_CALL(*offload_service_utils_, IsOffloadScanSupported())
+        .Times(1)
+        .WillRepeatedly(Return(false));
+  ScannerImpl scanner_impl(kFakeInterfaceIndex, scan_capabilities_test_frequencies,
+                           wiphy_features_, &client_interface_impl_,
+                           &scan_utils_, offload_service_utils_);
+
+  PnoSettings pno_settings;
+  PnoNetwork network;
+  PnoNetwork network2;
+  network.is_hidden_ = false;
+  network.frequencies_.push_back(2412);
+  network.frequencies_.push_back(2437);
+  network2.is_hidden_ = false;
+  network2.frequencies_.push_back(2437);
+  network2.frequencies_.push_back(2462);
+  pno_settings.pno_networks_.push_back(network);
+  pno_settings.pno_networks_.push_back(network2);
+
+  std::vector<uint32_t> expected_freqs;
+  expected_freqs.push_back(2412);
+  expected_freqs.push_back(2437);
+  expected_freqs.push_back(2462);
+  EXPECT_CALL(
+      scan_utils_,
+      StartScheduledScan(_, _, _, _, _, _, _, Eq(expected_freqs), _)).
+          WillOnce(Return(true));
+  EXPECT_TRUE(scanner_impl.startPnoScan(pno_settings, &success).isOk());
+  EXPECT_TRUE(success);
+}
+
+// Verify that if more than 30% of networks don't have frequency data then a list of default
+// frequencies will be added to the scan.
+TEST_F(ScannerTest, TestStartPnoScanWithFrequencyListFallbackMechanism) {
+  bool success = false;
+  ScanCapabilities scan_capabilities_test_frequencies(
+      1 /* max_num_scan_ssids */,
+      1 /* max_num_sched_scan_ssids */,
+      2 /* max_match_sets */,
+      0,
+      kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier / 1000,
+      PnoSettings::kFastScanIterations);
+  EXPECT_CALL(*offload_service_utils_, IsOffloadScanSupported())
+        .Times(1)
+        .WillRepeatedly(Return(false));
+  ScannerImpl scanner_impl(kFakeInterfaceIndex, scan_capabilities_test_frequencies,
+                           wiphy_features_, &client_interface_impl_,
+                           &scan_utils_, offload_service_utils_);
+
+  PnoSettings pno_settings;
+  PnoNetwork network;
+  PnoNetwork network2;
+  network.is_hidden_ = false;
+  network.frequencies_.push_back(5640);
+  network2.is_hidden_ = false;
+  pno_settings.pno_networks_.push_back(network);
+  pno_settings.pno_networks_.push_back(network2);
+
+  std::set<int32_t> default_frequencies = {2412, 2417, 2422, 2427, 2432, 2437, 2447, 2452, 2457,
+      2462, 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805};
+  default_frequencies.insert(5640); // add frequency from saved network
+  vector<uint32_t> expected_frequencies(default_frequencies.begin(), default_frequencies.end());
+  EXPECT_CALL(
+      scan_utils_,
+      StartScheduledScan(_, _, _, _, _, _, _, Eq(expected_frequencies), _)).
+          WillOnce(Return(true));
+  EXPECT_TRUE(scanner_impl.startPnoScan(pno_settings, &success).isOk());
+  EXPECT_TRUE(success);
+}
+
+// Verify that when there is no frequency data all pno networks, an empty list is passed into
+// StartScheduledScan in order to scan all frequencies.
+TEST_F(ScannerTest, TestStartPnoScanEmptyList) {
+  bool success = false;
+  ScanCapabilities scan_capabilities_test_frequencies(
+      1 /* max_num_scan_ssids */,
+      1 /* max_num_sched_scan_ssids */,
+      2 /* max_match_sets */,
+      0,
+      kFakeScanIntervalMs * PnoSettings::kSlowScanIntervalMultiplier / 1000,
+      PnoSettings::kFastScanIterations);
+  EXPECT_CALL(*offload_service_utils_, IsOffloadScanSupported())
+        .Times(1)
+        .WillRepeatedly(Return(false));
+  ScannerImpl scanner_impl(kFakeInterfaceIndex, scan_capabilities_test_frequencies,
+                           wiphy_features_, &client_interface_impl_,
+                           &scan_utils_, offload_service_utils_);
+
+  PnoSettings pno_settings;
+  PnoNetwork network;
+  PnoNetwork network2;
+  network.is_hidden_ = false;
+  network2.is_hidden_ = false;
+  pno_settings.pno_networks_.push_back(network);
+  pno_settings.pno_networks_.push_back(network2);
+  EXPECT_CALL(
+      scan_utils_,
+      StartScheduledScan(_, _, _, _, _, _, _, Eq(vector<uint32_t>{}), _)).
+          WillOnce(Return(true));
+  EXPECT_TRUE(scanner_impl.startPnoScan(pno_settings, &success).isOk());
+  EXPECT_TRUE(success);
+}
+
 }  // namespace wificond
 }  // namespace android
diff --git a/tests/server_unittest.cpp b/tests/server_unittest.cpp
index 58a275c..2175cf9 100644
--- a/tests/server_unittest.cpp
+++ b/tests/server_unittest.cpp
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
+#include <array>
 #include <memory>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-#include <wifi_system_test/mock_hostapd_manager.h>
 #include <wifi_system_test/mock_interface_tool.h>
-#include <wifi_system_test/mock_supplicant_manager.h>
 
 #include "android/net/wifi/IApInterface.h"
 #include "wificond/tests/mock_netlink_manager.h"
@@ -30,12 +29,8 @@
 
 using android::net::wifi::IApInterface;
 using android::net::wifi::IClientInterface;
-using android::wifi_system::HostapdManager;
 using android::wifi_system::InterfaceTool;
-using android::wifi_system::MockHostapdManager;
 using android::wifi_system::MockInterfaceTool;
-using android::wifi_system::MockSupplicantManager;
-using android::wifi_system::SupplicantManager;
 using std::unique_ptr;
 using std::vector;
 using testing::Eq;
@@ -59,9 +54,9 @@
 const uint32_t kFakeInterfaceIndex = 34;
 const uint32_t kFakeInterfaceIndex1 = 36;
 const uint32_t kFakeInterfaceIndexP2p = 36;
-const uint8_t kFakeInterfaceMacAddress[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
-const uint8_t kFakeInterfaceMacAddress1[] = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
-const uint8_t kFakeInterfaceMacAddressP2p[] = {0x15, 0x24, 0xef, 0x27, 0x12, 0xff};
+const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress1 = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
+const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddressP2p = {0x15, 0x24, 0xef, 0x27, 0x12, 0xff};
 
 // This is a helper function to mock the behavior of
 // NetlinkUtils::GetInterfaces().
@@ -85,16 +80,13 @@
   void SetUp() override {
     ON_CALL(*if_tool_, SetUpState(_, _)).WillByDefault(Return(true));
     ON_CALL(*netlink_utils_, GetWiphyIndex(_)).WillByDefault(Return(true));
+    ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(Return(true));
     ON_CALL(*netlink_utils_, GetInterfaces(_, _))
       .WillByDefault(Invoke(bind(
           MockGetInterfacesResponse, mock_interfaces, true, _1, _2)));
   }
 
   NiceMock<MockInterfaceTool>* if_tool_ = new NiceMock<MockInterfaceTool>;
-  NiceMock<MockSupplicantManager>* supplicant_manager_ =
-      new NiceMock<MockSupplicantManager>;
-  NiceMock<MockHostapdManager>* hostapd_manager_ =
-      new NiceMock<MockHostapdManager>;
 
   unique_ptr<NiceMock<MockNetlinkManager>> netlink_manager_{
       new NiceMock<MockNetlinkManager>()};
@@ -108,28 +100,20 @@
       InterfaceInfo(
           kFakeInterfaceIndex,
           std::string(kFakeInterfaceName),
-          vector<uint8_t>(
-              kFakeInterfaceMacAddress,
-              kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress))),
+          std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddress)),
       // AP Interface
       InterfaceInfo(
           kFakeInterfaceIndex1,
           std::string(kFakeInterfaceName1),
-          vector<uint8_t>(
-              kFakeInterfaceMacAddress1,
-              kFakeInterfaceMacAddress1 + sizeof(kFakeInterfaceMacAddress1))),
+          std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddress1)),
       // p2p interface
       InterfaceInfo(
           kFakeInterfaceIndexP2p,
           std::string(kFakeInterfaceNameP2p),
-           vector<uint8_t>(
-               kFakeInterfaceMacAddressP2p,
-               kFakeInterfaceMacAddressP2p + sizeof(kFakeInterfaceMacAddressP2p)))
+          std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddressP2p))
   };
 
   Server server_{unique_ptr<InterfaceTool>(if_tool_),
-                 unique_ptr<SupplicantManager>(supplicant_manager_),
-                 unique_ptr<HostapdManager>(hostapd_manager_),
                  netlink_utils_.get(),
                  scan_utils_.get()};
 };  // class ServerTest
@@ -172,9 +156,6 @@
 TEST_F(ServerTest, CanTeardownApInterface) {
   sp<IApInterface> ap_if;
 
-  // When we tear down the interface, we expect the iface to be unloaded.
-  EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName), Eq(false)));
-
   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
   EXPECT_NE(nullptr, ap_if.get());
 
@@ -191,9 +172,6 @@
 TEST_F(ServerTest, CanTeardownClientInterface) {
   sp<IClientInterface> client_if;
 
-  // When we tear down the interface, we expect the iface to be unloaded.
-  EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName), Eq(false)));
-
   EXPECT_TRUE(server_.createClientInterface(
       kFakeInterfaceName, &client_if).isOk());
   EXPECT_NE(nullptr, client_if.get());
@@ -209,38 +187,6 @@
   EXPECT_TRUE(success);
 }
 
-TEST_F(ServerTest, ShouldReportEnableFailure) {
-  EXPECT_CALL(*supplicant_manager_, StartSupplicant())
-      .WillOnce(Return(false));
-  bool success = true;
-  EXPECT_TRUE(server_.enableSupplicant(&success).isOk());
-  EXPECT_FALSE(success);
-}
-
-TEST_F(ServerTest, ShouldReportenableSuccess) {
-  EXPECT_CALL(*supplicant_manager_, StartSupplicant())
-      .WillOnce(Return(true));
-  bool success = false;
-  EXPECT_TRUE(server_.enableSupplicant(&success).isOk());
-  EXPECT_TRUE(success);
-}
-
-TEST_F(ServerTest, ShouldReportDisableFailure) {
-  EXPECT_CALL(*supplicant_manager_, StopSupplicant())
-      .WillOnce(Return(false));
-  bool success = true;
-  EXPECT_TRUE(server_.disableSupplicant(&success).isOk());
-  EXPECT_FALSE(success);
-}
-
-TEST_F(ServerTest, ShouldReportDisableSuccess) {
-  EXPECT_CALL(*supplicant_manager_, StopSupplicant())
-      .WillOnce(Return(true));
-  bool success = false;
-  EXPECT_TRUE(server_.disableSupplicant(&success).isOk());
-  EXPECT_TRUE(success);
-}
-
 TEST_F(ServerTest, CanCreateTeardownApAndClientInterface) {
   sp<IClientInterface> client_if;
   sp<IApInterface> ap_if;
@@ -251,10 +197,6 @@
   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName1, &ap_if).isOk());
   EXPECT_NE(nullptr, ap_if.get());
 
-  // When we tear down the interfaces, we expect the iface to be unloaded.
-  EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName), Eq(false)));
-  EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName1), Eq(false)));
-
   bool success = true;
   // Try to remove an invalid iface name, this should fail.
   EXPECT_TRUE(server_.tearDownClientInterface(