hostapd(hidl): Add helper functions for writing config file

The HIDL interface for hostapd is a wrapper used to create hostapd conf file.
This file will be then be passed to the hostapd core to avoid
duplication of the conf parsing.

Note: This is a port of the methods in HostapdManager.

Bug: 36646171
Test: Compiles with CONFIG_CTRL_IFACE_HIDL=y in android.config
Change-Id: If11e3f795c05f34442566343ae02bc2a385890a6
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 77533d7..b19a74a 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1109,7 +1109,7 @@
 endif
 ifeq ($(HOSTAPD_USE_HIDL), y)
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
-LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils
+LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidltransport libhwbinder libutils
 LOCAL_STATIC_LIBRARIES += libhostapd_hidl
 endif
 LOCAL_CFLAGS := $(L_CFLAGS)
@@ -1133,6 +1133,7 @@
     hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi.hostapd@1.0 \
+    libbase \
     libhidlbase \
     libhidltransport \
     libhwbinder \
diff --git a/hostapd/android.config b/hostapd/android.config
index 3e40aa1..9dfdb28 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -213,4 +213,4 @@
 
 # Add support for Hidl control interface
 # Only applicable for Android platforms.
-CONFIG_CTRL_IFACE_HIDL=n
+CONFIG_CTRL_IFACE_HIDL=y
diff --git a/hostapd/hidl/1.0/hostapd.cpp b/hostapd/hidl/1.0/hostapd.cpp
index 8834a82..fc07f06 100644
--- a/hostapd/hidl/1.0/hostapd.cpp
+++ b/hostapd/hidl/1.0/hostapd.cpp
@@ -6,10 +6,170 @@
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
  */
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 
 #include "hostapd.h"
 #include "hidl_return_util.h"
 
+// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
+// each interface. This file can then be used to hook onto the normal config
+// file parsing logic in hostapd code.  Helps us to avoid duplication of code
+// in the HIDL interface.
+// TOOD(b/71872409): Add unit tests for this.
+namespace {
+constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
+
+using android::base::RemoveFileIfExists;
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+using android::hardware::wifi::hostapd::V1_0::IHostapd;
+
+std::string WriteHostapdConfig(
+    const std::string& interface_name, const std::string& config)
+{
+	const std::string file_path =
+	    StringPrintf(kConfFileNameFmt, interface_name.c_str());
+	if (WriteStringToFile(
+		config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+		getuid(), getgid())) {
+		return file_path;
+	}
+	// Diagnose failure
+	int error = errno;
+	wpa_printf(
+	    MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
+	    file_path.c_str(), strerror(error));
+	struct stat st;
+	int result = stat(file_path.c_str(), &st);
+	if (result == 0) {
+		wpa_printf(
+		    MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
+		    st.st_uid, st.st_gid, st.st_mode);
+	} else {
+		wpa_printf(
+		    MSG_ERROR,
+		    "Error calling stat() on hostapd config file: %s",
+		    strerror(errno));
+	}
+	return "";
+}
+
+std::string CreateHostapdConfig(
+    const IHostapd::IfaceParams& iface_params,
+    const IHostapd::NetworkParams& nw_params)
+{
+	if (nw_params.ssid.size() >
+	    static_cast<uint32_t>(
+		IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
+		wpa_printf(
+		    MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size());
+		return "";
+	}
+	if (nw_params.pskPassphrase.size() <
+		static_cast<uint32_t>(
+		    IHostapd::ParamSizeLimits::
+			WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
+	    nw_params.pskPassphrase.size() >
+		static_cast<uint32_t>(
+		    IHostapd::ParamSizeLimits::
+			WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES)) {
+		wpa_printf(
+		    MSG_ERROR, "Invalid psk passphrase size: %zu",
+		    nw_params.pskPassphrase.size());
+		return "";
+	}
+
+	// SSID string
+	std::stringstream ss;
+	ss << std::hex;
+	ss << std::setfill('0');
+	for (uint8_t b : nw_params.ssid) {
+		ss << std::setw(2) << static_cast<unsigned int>(b);
+	}
+	const std::string ssid_as_string = ss.str();
+
+	// Encryption config string
+	std::string encryption_config_as_string;
+	switch (nw_params.encryptionType) {
+	case IHostapd::EncryptionType::NONE:
+		// no security params
+		break;
+	case IHostapd::EncryptionType::WPA:
+		encryption_config_as_string = StringPrintf(
+		    "wpa=3\n"
+		    "wpa_pairwise=TKIP CCMP\n"
+		    "wpa_passphrase=%s",
+		    nw_params.pskPassphrase.c_str());
+		break;
+	case IHostapd::EncryptionType::WPA2:
+		encryption_config_as_string = StringPrintf(
+		    "wpa=2\n"
+		    "rsn_pairwise=CCMP\n"
+		    "wpa_passphrase=%s",
+		    nw_params.pskPassphrase.c_str());
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "Unknown encryption type");
+		return "";
+	}
+
+	std::string channel_config_as_string;
+	if (iface_params.channelParams.enableAcs) {
+		channel_config_as_string = StringPrintf(
+		    "channel=0\n"
+		    "acs_exclude_dfs=%d",
+		    iface_params.channelParams.acsShouldExcludeDfs);
+	} else {
+		channel_config_as_string = StringPrintf(
+		    "channel=%d", iface_params.channelParams.channel);
+	}
+
+	// Hw Mode String
+	std::string hw_mode_as_string;
+	switch (iface_params.channelParams.band) {
+	case IHostapd::Band::BAND_2_4_GHZ:
+		hw_mode_as_string = "g";
+		break;
+	case IHostapd::Band::BAND_5_GHZ:
+		hw_mode_as_string = "a";
+		break;
+	case IHostapd::Band::BAND_ANY:
+		hw_mode_as_string = "any";
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "Invalid band");
+		return "";
+	}
+
+	return StringPrintf(
+	    "interface=%s\n"
+	    "driver=nl80211\n"
+	    // ssid2 signals to hostapd that the value is not a literal value
+	    // for use as a SSID.  In this case, we're giving it a hex
+	    // std::string and hostapd needs to expect that.
+	    "ssid2=%s\n"
+	    "%s\n"
+	    "ieee80211n=%d\n"
+	    "ieee80211ac=%d\n"
+	    "hw_mode=%s\n"
+	    "ignore_broadcast_ssid=%d\n"
+	    "wowlan_triggers=any\n"
+	    "%s\n",
+	    iface_params.ifaceName.c_str(), ssid_as_string.c_str(),
+	    channel_config_as_string.c_str(),
+	    iface_params.hwModeParams.enable80211N ? 1 : 0,
+	    iface_params.hwModeParams.enable80211AC ? 1 : 0,
+	    hw_mode_as_string.c_str(), nw_params.isHidden ? 1 : 0,
+	    encryption_config_as_string.c_str());
+}
+}  // namespace
+
 namespace android {
 namespace hardware {
 namespace wifi {