blob: 696e1239400975aef3d4e357c80d5f8035db796e [file] [log] [blame]
/*
* Copyright (C) 2024 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 <cstring>
#include <gtest/gtest.h>
#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*)
* There's an || check on these that should return nullopt
*/
TEST(getStaInfoByMacAddrTest, NullArguments) {
EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(nullptr, nullptr));
}
/**
* We pass valid arguments to get past the nullptr check, but hostapd_data->sta_list is nullptr.
* Don't loop through the sta_info* list, just return nullopt.
*/
TEST(getStaInfoByMacAddrTest, NullStaList) {
struct hostapd_data iface_hapd = {};
u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(&iface_hapd, mac_addr));
}
/**
* Mac doesn't match, and we hit the end of the sta_info list.
* Don't run over the end of the list and return nullopt.
*/
TEST(getStaInfoByMacAddrTest, NoMatchingMac) {
struct hostapd_data iface_hapd = {};
struct sta_info sta0 = {};
struct sta_info sta1 = {};
struct sta_info sta2 = {};
iface_hapd.sta_list = &sta0;
sta0.next = &sta1;
sta1.next = &sta2;
u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(&iface_hapd, mac_addr));
}
/**
* There is a matching address and we return it.
*/
TEST(getStaInfoByMacAddrTest, MatchingMac) {
struct hostapd_data iface_hapd = {};
struct sta_info sta0 = {};
struct sta_info sta1 = {};
struct sta_info sta2 = {};
iface_hapd.sta_list = &sta0;
sta0.next = &sta1;
sta1.next = &sta2;
u8 sta0_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0C}; // off by 1 bit
std::memcpy(sta0.addr, sta0_addr, ETH_ALEN);
u8 sta1_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
std::memcpy(sta1.addr, sta1_addr, ETH_ALEN);
u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
auto sta_ptr_optional = getStaInfoByMacAddr(&iface_hapd, mac_addr);
EXPECT_TRUE(sta_ptr_optional.has_value());
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