Add overlay support for hostapd

Adds support for reading an overlay file for LOHS to add additional
configurability.

Bug: 361651437
Test: included unit tests
Change-Id: Iff836d978c90c08144a4eaf746d0e0880f7c165b
diff --git a/hostapd/aidl/tests/unittests.cpp b/hostapd/aidl/tests/unittests.cpp
index 900f043..696e123 100644
--- a/hostapd/aidl/tests/unittests.cpp
+++ b/hostapd/aidl/tests/unittests.cpp
@@ -20,6 +20,111 @@
 #include "../hostapd.cpp"
 
 namespace aidl::android::hardware::wifi::hostapd {
+unsigned char kTestSsid[] = {0x31, 0x32, 0x33, 0x61, 0x62, 0x63, 0x64};
+
+class HostapdConfigTest : public testing::Test {
+	protected:
+	void SetUp() override {
+		resetOverrides();
+
+		mIface_params = {
+			.name = "wlan42",
+			.hwModeParams = {
+				.enable80211N = true,
+				.enable80211AC = false,
+				.enable80211AX = false,
+				.enable6GhzBand = false,
+				.enableHeSingleUserBeamformer = false,
+				.enableHeSingleUserBeamformee = false,
+				.enableHeMultiUserBeamformer = false,
+				.enableHeTargetWakeTime = false,
+				.enableEdmg = false,
+				.enable80211BE = false,
+				.maximumChannelBandwidth = ChannelBandwidth::BANDWIDTH_AUTO,
+			},
+			.channelParams = {},  // not used in config creation
+			.vendorData = {},  // not used in config creation
+			.instanceIdentities = {},  // not used in config creation
+			.usesMlo = false,
+		};
+		mChannel_params = {
+			.bandMask = BandMask::BAND_2_GHZ,
+			.acsChannelFreqRangesMhz = {},
+			.enableAcs = false,
+			.acsShouldExcludeDfs = false,
+			.channel = 6,
+		};
+		mNetwork_params = {
+			.ssid =  std::vector<uint8_t>(kTestSsid, kTestSsid + sizeof(kTestSsid)),
+			.isHidden = false,
+			.encryptionType = EncryptionType::WPA2,
+			.passphrase = "verysecurewowe",
+			.isMetered = true,  // default for tethered softap, change to false for lohs.
+			.vendorElements = {},
+		};
+	}
+
+	std::string mWlan42_tethered_config = "\ninterface=wlan42\n"
+		"driver=nl80211\n"
+		"ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+		"ssid2=31323361626364\n"
+		"channel=6\n"
+		"op_class=83\n"
+		"ieee80211n=1\n"
+		"ieee80211ac=0\n\n\n"
+		"hw_mode=g\n\n"
+		"ignore_broadcast_ssid=0\n"
+		"wowlan_triggers=any\n"
+		"interworking=1\n"
+		"access_network_type=2\n\n"
+		"wpa=2\n"
+		"rsn_pairwise=CCMP\n"
+		"wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+		"ap_isolate=0\n";
+
+	std::string mWlan42_lohs_config = "dtim_period=2   \n"
+		"   ap_max_inactivity=300\n"
+		"skip_inactivity_poll = 1\n\n"
+		"interface=wlan42\n"
+		"driver=nl80211\n"
+		"ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+		"ssid2=31323361626364\n"
+		"channel=6\n"
+		"op_class=83\n"
+		"ieee80211n=1\n"
+		"ieee80211ac=0\n\n\n"
+		"hw_mode=g\n\n"
+		"ignore_broadcast_ssid=0\n"
+		"wowlan_triggers=any\n"
+		"interworking=0\n\n"
+		"wpa=2\n"
+		"rsn_pairwise=CCMP\n"
+		"wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+		"ap_isolate=0\n";
+
+	std::string mWlan42_lohs_config_no_overlay = "\ninterface=wlan42\n"
+		"driver=nl80211\n"
+		"ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+		"ssid2=31323361626364\n"
+		"channel=6\n"
+		"op_class=83\n"
+		"ieee80211n=1\n"
+		"ieee80211ac=0\n\n\n"
+		"hw_mode=g\n\n"
+		"ignore_broadcast_ssid=0\n"
+		"wowlan_triggers=any\n"
+		"interworking=0\n\n"
+		"wpa=2\n"
+		"rsn_pairwise=CCMP\n"
+		"wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+		"ap_isolate=0\n";
+
+	IfaceParams mIface_params;
+	ChannelParams mChannel_params;
+	NetworkParams mNetwork_params;
+	std::string mBr_name = "";
+	std::string mOwe_transition_ifname = "";
+};
 
 /**
  * Null hostapd_data* and null mac address (u8*)
@@ -59,7 +164,7 @@
 /**
  * There is a matching address and we return it.
  */
-TEST(getStaInfoByMacAddr, MatchingMac) {
+TEST(getStaInfoByMacAddrTest, MatchingMac) {
 	struct hostapd_data iface_hapd = {};
 	struct sta_info sta0 = {};
 	struct sta_info sta1 = {};
@@ -77,4 +182,65 @@
 	EXPECT_EQ(0, std::memcmp(sta_ptr_optional.value()->addr, sta1_addr, ETH_ALEN));
 }
 
+
+TEST_F(HostapdConfigTest, tetheredApConfig) {
+	// instance name, config string, br_name, usesMlo
+	std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+	std::string expected_path = "/data/vendor/wifi/hostapd/hostapd_wlan42.conf";
+	EXPECT_EQ(expected_path, config_path);
+	EXPECT_EQ(mWlan42_tethered_config, hostapd_unittest_config_output);
+}
+
+TEST_F(HostapdConfigTest, tetheredApConfigStatFails) {
+	hostapd_unittest_WriteStringToFileRet = false;
+	hostapd_unittest_stat_ret = -1;
+	// instance name, config string, br_name, usesMlo
+	std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+	std::string expected_path = "";
+	EXPECT_EQ(expected_path, config_path);
+}
+
+TEST_F(HostapdConfigTest, tetheredApConfigWriteFails) {
+	hostapd_unittest_WriteStringToFileRet = false;
+	// instance name, config string, br_name, usesMlo
+	std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+	std::string expected_path = "";
+	EXPECT_EQ(expected_path, config_path);
+}
+
+TEST_F(HostapdConfigTest, tetheredAp) {
+	std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+			mBr_name, mOwe_transition_ifname);
+	EXPECT_EQ(mWlan42_tethered_config, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsAp) {
+	mNetwork_params.isMetered = false;
+	hostapd_unittest_overlay_content =
+			"invalid_key=this_should_not_be_here\n"
+			"dtim_period=2   \n"
+			"   ap_max_inactivity=300\n"
+			"another_invalid_key_dtim_period=-10000\n"
+			"skip_inactivity_poll = 1";
+	std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+			mBr_name, mOwe_transition_ifname);
+	EXPECT_EQ(mWlan42_lohs_config, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsApAccessFails) {
+	mNetwork_params.isMetered = false;
+	hostapd_unittest_accessRet = -1;
+	std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+			mBr_name, mOwe_transition_ifname);
+	EXPECT_EQ(mWlan42_lohs_config_no_overlay, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsApReadFails) {
+	mNetwork_params.isMetered = false;
+	hostapd_unittest_ReadFileToStringRet = false;
+	std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+			mBr_name, mOwe_transition_ifname);
+	EXPECT_EQ("", config_string);
+}
+
 }  // namespace aidl::android::hardware::wifi::hostapd