/* * 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 #include #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(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