wpa_supplicant(hidl): Add support for "DRIVER" commands

Bug: 32699292
Test: Compiles
Change-Id: I6b83c2e5884d759824a8cbd5c125d1853766d823
diff --git a/wpa_supplicant/hidl/p2p_iface.cpp b/wpa_supplicant/hidl/p2p_iface.cpp
index 6ad0696..6251339 100644
--- a/wpa_supplicant/hidl/p2p_iface.cpp
+++ b/wpa_supplicant/hidl/p2p_iface.cpp
@@ -15,6 +15,22 @@
 const char kConfigMethodStrPbc[] = "pbc";
 const char kConfigMethodStrDisplay[] = "display";
 const char kConfigMethodStrKeypad[] = "keypad";
+constexpr char kSetMiracastMode[] = "MIRACAST ";
+
+using android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
+uint8_t convertHidlMiracastModeToInternal(
+    ISupplicantP2pIface::MiracastMode mode)
+{
+	switch (mode) {
+	case ISupplicantP2pIface::MiracastMode::DISABLED:
+		return 0;
+	case ISupplicantP2pIface::MiracastMode::SOURCE:
+		return 1;
+	case ISupplicantP2pIface::MiracastMode::SINK:
+		return 2;
+	};
+	WPA_ASSERT(false);
+}
 }  // namespace
 
 namespace android {
@@ -326,6 +342,14 @@
 	    &P2pIface::cancelServiceDiscoveryInternal, _hidl_cb, identifier);
 }
 
+Return<void> P2pIface::setMiracastMode(
+    ISupplicantP2pIface::MiracastMode mode, setMiracastMode_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &P2pIface::setMiracastModeInternal, _hidl_cb, mode);
+}
+
 std::pair<SupplicantStatus, std::string> P2pIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -837,6 +861,24 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+SupplicantStatus P2pIface::setMiracastModeInternal(
+    ISupplicantP2pIface::MiracastMode mode)
+{
+	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	uint8_t mode_internal = convertHidlMiracastModeToInternal(mode);
+	const std::string cmd_str =
+	    kSetMiracastMode + std::to_string(mode_internal);
+	std::vector<char> cmd(
+	    cmd_str.c_str(), cmd_str.c_str() + cmd_str.size() + 1);
+	char driver_cmd_reply_buf[4096] = {};
+	if (wpa_drv_driver_cmd(
+		wpa_s, cmd.data(), driver_cmd_reply_buf,
+		sizeof(driver_cmd_reply_buf))) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
diff --git a/wpa_supplicant/hidl/p2p_iface.h b/wpa_supplicant/hidl/p2p_iface.h
index 312b8bb..c83f43b 100644
--- a/wpa_supplicant/hidl/p2p_iface.h
+++ b/wpa_supplicant/hidl/p2p_iface.h
@@ -139,6 +139,9 @@
 	    requestServiceDiscovery_cb _hidl_cb) override;
 	Return<void> cancelServiceDiscovery(
 	    uint64_t identifier, cancelServiceDiscovery_cb _hidl_cb) override;
+	Return<void> setMiracastMode(
+	    ISupplicantP2pIface::MiracastMode mode,
+	    setMiracastMode_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -211,6 +214,8 @@
 	    const std::array<uint8_t, 6>& peer_address,
 	    const std::vector<uint8_t>& query);
 	SupplicantStatus cancelServiceDiscoveryInternal(uint64_t identifier);
+	SupplicantStatus setMiracastModeInternal(
+	    ISupplicantP2pIface::MiracastMode mode);
 
 	struct wpa_supplicant* retrieveIfacePtr();
 	struct wpa_supplicant* retrieveGroupIfacePtr(
diff --git a/wpa_supplicant/hidl/sta_iface.cpp b/wpa_supplicant/hidl/sta_iface.cpp
index a60267d..a513260 100644
--- a/wpa_supplicant/hidl/sta_iface.cpp
+++ b/wpa_supplicant/hidl/sta_iface.cpp
@@ -19,6 +19,74 @@
 
 namespace {
 constexpr uint32_t kMaxAnqpElems = 100;
+constexpr char kGetMacAddress[] = "MACADDR";
+constexpr char kStartRxFilter[] = "RXFILTER-START";
+constexpr char kStopRxFilter[] = "RXFILTER-STOP";
+constexpr char kAddRxFilter[] = "RXFILTER-ADD";
+constexpr char kRemoveRxFilter[] = "RXFILTER-REMOVE";
+constexpr char kSetBtCoexistenceMode[] = "BTCOEXMODE";
+constexpr char kSetBtCoexistenceScanStart[] = "BTCOEXSCAN-START";
+constexpr char kSetBtCoexistenceScanStop[] = "BTCOEXSCAN-STOP";
+constexpr char kSetSupendModeEnabled[] = "SETSUSPENDMODE 1";
+constexpr char kSetSupendModeDisabled[] = "SETSUSPENDMODE 0";
+constexpr char kSetCountryCode[] = "COUNTRY ";
+
+using android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+uint8_t convertHidlRxFilterTypeToInternal(
+    ISupplicantStaIface::RxFilterType type)
+{
+	switch (type) {
+	case ISupplicantStaIface::RxFilterType::V4_MULTICAST:
+		return 2;
+	case ISupplicantStaIface::RxFilterType::V6_MULTICAST:
+		return 3;
+	};
+	WPA_ASSERT(false);
+}
+
+uint8_t convertHidlBtCoexModeToInternal(
+    ISupplicantStaIface::BtCoexistenceMode mode)
+{
+	switch (mode) {
+	case ISupplicantStaIface::BtCoexistenceMode::ENABLED:
+		return 0;
+	case ISupplicantStaIface::BtCoexistenceMode::DISABLED:
+		return 1;
+	case ISupplicantStaIface::BtCoexistenceMode::SENSE:
+		return 2;
+	};
+	WPA_ASSERT(false);
+}
+
+SupplicantStatus doZeroArgDriverCommand(
+    struct wpa_supplicant *wpa_s, const char *cmd)
+{
+	std::vector<char> cmd_vec(cmd, cmd + strlen(cmd) + 1);
+	char driver_cmd_reply_buf[4096] = {};
+	if (wpa_drv_driver_cmd(
+		wpa_s, cmd_vec.data(), driver_cmd_reply_buf,
+		sizeof(driver_cmd_reply_buf))) {
+		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
+SupplicantStatus doOneArgDriverCommand(
+    struct wpa_supplicant *wpa_s, const char *cmd, uint8_t arg)
+{
+	std::string cmd_str = std::string(cmd) + " " + std::to_string(arg);
+	return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
+}
+
+SupplicantStatus doOneArgDriverCommand(
+    struct wpa_supplicant *wpa_s, const char *cmd, const std::string &arg)
+{
+	std::string cmd_str = std::string(cmd) + " " + arg;
+	return doZeroArgDriverCommand(wpa_s, cmd_str.c_str());
+}
 }  // namespace
 
 namespace android {
@@ -166,6 +234,77 @@
 	    file_name);
 }
 
+Return<void> StaIface::getMacAddress(getMacAddress_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::getMacAddressInternal, _hidl_cb);
+}
+
+Return<void> StaIface::startRxFilter(startRxFilter_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::startRxFilterInternal, _hidl_cb);
+}
+
+Return<void> StaIface::stopRxFilter(stopRxFilter_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::stopRxFilterInternal, _hidl_cb);
+}
+
+Return<void> StaIface::addRxFilter(
+    ISupplicantStaIface::RxFilterType type, addRxFilter_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::addRxFilterInternal, _hidl_cb, type);
+}
+
+Return<void> StaIface::removeRxFilter(
+    ISupplicantStaIface::RxFilterType type, removeRxFilter_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::removeRxFilterInternal, _hidl_cb, type);
+}
+
+Return<void> StaIface::setBtCoexistenceMode(
+    ISupplicantStaIface::BtCoexistenceMode mode,
+    setBtCoexistenceMode_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::setBtCoexistenceModeInternal, _hidl_cb, mode);
+}
+
+Return<void> StaIface::setBtCoexistenceScanModeEnabled(
+    bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::setBtCoexistenceScanModeEnabledInternal, _hidl_cb,
+	    enable);
+}
+
+Return<void> StaIface::setSuspendModeEnabled(
+    bool enable, setSuspendModeEnabled_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::setSuspendModeEnabledInternal, _hidl_cb, enable);
+}
+
+Return<void> StaIface::setCountryCode(
+    const hidl_array<int8_t, 2> &code, setCountryCode_cb _hidl_cb)
+{
+	return validateAndCall(
+	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+	    &StaIface::setCountryCodeInternal, _hidl_cb, code);
+}
+
 std::pair<SupplicantStatus, std::string> StaIface::getNameInternal()
 {
 	return {{SupplicantStatusCode::SUCCESS, ""}, ifname_};
@@ -398,6 +537,112 @@
 	return {SupplicantStatusCode::SUCCESS, ""};
 }
 
+std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+StaIface::getMacAddressInternal()
+{
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	std::vector<char> cmd(
+	    kGetMacAddress, kGetMacAddress + sizeof(kGetMacAddress));
+	char driver_cmd_reply_buf[4096] = {};
+	int ret = wpa_drv_driver_cmd(
+	    wpa_s, cmd.data(), driver_cmd_reply_buf,
+	    sizeof(driver_cmd_reply_buf));
+	// Reply is of the format: "Macaddr = XX:XX:XX:XX:XX:XX"
+	std::string reply_str = driver_cmd_reply_buf;
+	if (ret || reply_str.empty() ||
+	    reply_str.find("=") == std::string::npos) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+	}
+	// Remove all whitespace first and then split using the delimiter "=".
+	reply_str.erase(
+	    remove_if(reply_str.begin(), reply_str.end(), isspace),
+	    reply_str.end());
+	std::string mac_addr_str =
+	    reply_str.substr(reply_str.find("=") + 1, reply_str.size());
+	std::array<uint8_t, 6> mac_addr;
+	if (hwaddr_aton(mac_addr_str.c_str(), mac_addr.data())) {
+		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
+	}
+	return {{SupplicantStatusCode::SUCCESS, ""}, mac_addr};
+}
+
+SupplicantStatus StaIface::startRxFilterInternal()
+{
+	return doZeroArgDriverCommand(retrieveIfacePtr(), kStartRxFilter);
+}
+
+SupplicantStatus StaIface::stopRxFilterInternal()
+{
+	return doZeroArgDriverCommand(retrieveIfacePtr(), kStopRxFilter);
+}
+
+SupplicantStatus StaIface::addRxFilterInternal(
+    ISupplicantStaIface::RxFilterType type)
+{
+	return doOneArgDriverCommand(
+	    retrieveIfacePtr(), kAddRxFilter,
+	    convertHidlRxFilterTypeToInternal(type));
+}
+
+SupplicantStatus StaIface::removeRxFilterInternal(
+    ISupplicantStaIface::RxFilterType type)
+{
+	return doOneArgDriverCommand(
+	    retrieveIfacePtr(), kRemoveRxFilter,
+	    convertHidlRxFilterTypeToInternal(type));
+}
+
+SupplicantStatus StaIface::setBtCoexistenceModeInternal(
+    ISupplicantStaIface::BtCoexistenceMode mode)
+{
+	return doOneArgDriverCommand(
+	    retrieveIfacePtr(), kSetBtCoexistenceMode,
+	    convertHidlBtCoexModeToInternal(mode));
+}
+
+SupplicantStatus StaIface::setBtCoexistenceScanModeEnabledInternal(bool enable)
+{
+	const char *cmd;
+	if (enable) {
+		cmd = kSetBtCoexistenceScanStart;
+	} else {
+		cmd = kSetBtCoexistenceScanStop;
+	}
+	return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
+}
+
+SupplicantStatus StaIface::setSuspendModeEnabledInternal(bool enable)
+{
+	const char *cmd;
+	if (enable) {
+		cmd = kSetSupendModeEnabled;
+	} else {
+		cmd = kSetSupendModeDisabled;
+	}
+	return doZeroArgDriverCommand(retrieveIfacePtr(), cmd);
+}
+
+SupplicantStatus StaIface::setCountryCodeInternal(
+    const std::array<int8_t, 2> &code)
+{
+	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+	SupplicantStatus status = doOneArgDriverCommand(
+	    wpa_s, kSetCountryCode,
+	    std::string(std::begin(code), std::end(code)));
+	if (status.code != SupplicantStatusCode::SUCCESS) {
+		return status;
+	}
+	struct p2p_data *p2p = wpa_s->global->p2p;
+	if (p2p) {
+		char country[3];
+		country[0] = code[0];
+		country[1] = code[1];
+		country[2] = 0x04;
+		p2p_set_country(p2p, country);
+	}
+	return {SupplicantStatusCode::SUCCESS, ""};
+}
+
 /**
  * Retrieve the underlying |wpa_supplicant| struct
  * pointer for this iface.
@@ -408,7 +653,6 @@
 {
 	return wpa_supplicant_get_iface(wpa_global_, ifname_.c_str());
 }
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace wifi
diff --git a/wpa_supplicant/hidl/sta_iface.h b/wpa_supplicant/hidl/sta_iface.h
index 01b2b5e..3910143 100644
--- a/wpa_supplicant/hidl/sta_iface.h
+++ b/wpa_supplicant/hidl/sta_iface.h
@@ -96,6 +96,25 @@
 	    const hidl_array<uint8_t, 6>& mac_address,
 	    const hidl_string& file_name,
 	    initiateHs20IconQuery_cb _hidl_cb) override;
+	Return<void> getMacAddress(getMacAddress_cb _hidl_cb) override;
+	Return<void> startRxFilter(startRxFilter_cb _hidl_cb) override;
+	Return<void> stopRxFilter(stopRxFilter_cb _hidl_cb) override;
+	Return<void> addRxFilter(
+	    ISupplicantStaIface::RxFilterType type,
+	    addRxFilter_cb _hidl_cb) override;
+	Return<void> removeRxFilter(
+	    ISupplicantStaIface::RxFilterType type,
+	    removeRxFilter_cb _hidl_cb) override;
+	Return<void> setBtCoexistenceMode(
+	    ISupplicantStaIface::BtCoexistenceMode mode,
+	    setBtCoexistenceMode_cb _hidl_cb) override;
+	Return<void> setBtCoexistenceScanModeEnabled(
+	    bool enable, setBtCoexistenceScanModeEnabled_cb _hidl_cb) override;
+	Return<void> setSuspendModeEnabled(
+	    bool enable, setSuspendModeEnabled_cb _hidl_cb) override;
+	Return<void> setCountryCode(
+	    const hidl_array<int8_t, 2>& code,
+	    setCountryCode_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
@@ -128,6 +147,20 @@
 	SupplicantStatus initiateHs20IconQueryInternal(
 	    const std::array<uint8_t, 6>& mac_address,
 	    const std::string& file_name);
+	std::pair<SupplicantStatus, std::array<uint8_t, 6>>
+	getMacAddressInternal();
+	SupplicantStatus startRxFilterInternal();
+	SupplicantStatus stopRxFilterInternal();
+	SupplicantStatus addRxFilterInternal(
+	    ISupplicantStaIface::RxFilterType type);
+	SupplicantStatus removeRxFilterInternal(
+	    ISupplicantStaIface::RxFilterType type);
+	SupplicantStatus setBtCoexistenceModeInternal(
+	    ISupplicantStaIface::BtCoexistenceMode mode);
+	SupplicantStatus setBtCoexistenceScanModeEnabledInternal(bool enable);
+	SupplicantStatus setSuspendModeEnabledInternal(bool enable);
+	SupplicantStatus setCountryCodeInternal(
+	    const std::array<int8_t, 2>& code);
 
 	struct wpa_supplicant* retrieveIfacePtr();