diff --git a/src/linux/external/hostap/CMakeLists.txt b/src/linux/external/hostap/CMakeLists.txt index 1e34e1bc..4090fc9f 100644 --- a/src/linux/external/hostap/CMakeLists.txt +++ b/src/linux/external/hostap/CMakeLists.txt @@ -22,7 +22,7 @@ set(HOSTAP_TMP_DIR ${HOSTAP_PREFIX}/tmp) set(HOSTAP_STAMP_DIR ${HOSTAP_PREFIX}/src/${HOSTAP_EP_NAME}-stamp) set(HOSTAP_DOWNLOAD_DIR ${HOSTAP_PREFIX}/src) set(HOSTAP_SOURCE_DIR ${HOSTAP_PREFIX}/src/${HOSTAP_EP_NAME}) -set(HOSTAP_BINARY_DIR ${HOSTAP_PREFIX}/src/${HOSTAP_EP_NAME}-build) +set(HOSTAP_BINARY_DIR ${HOSTAP_SOURCE_DIR}/hostapd CACHE FILEPATH "hostapd binary directory" FORCE) set(HOSTAP_INSTALL_DIR ${HOSTAP_PREFIX}) set(HOSTAP_LOG_DIR ${HOSTAP_STAMP_DIR}) diff --git a/src/linux/wpa-controller/include/Wpa/ProtocolWpaConfig.hxx b/src/linux/wpa-controller/include/Wpa/ProtocolWpaConfig.hxx index daacd647..aa59fe42 100644 --- a/src/linux/wpa-controller/include/Wpa/ProtocolWpaConfig.hxx +++ b/src/linux/wpa-controller/include/Wpa/ProtocolWpaConfig.hxx @@ -6,6 +6,8 @@ #error "CONFIG_WPA_CONTROL_SOCKET_PATH_BASE must be defined." #endif +#include + namespace Wpa { /** @@ -29,6 +31,27 @@ struct ProtocolWpaConfig * @brief The path to the control sockets used by hostapd. */ static constexpr auto ControlSocketPathHostapd{ CONFIG_WPA_CONTROL_SOCKET_PATH_BASE "/hostapd" }; + + /** + * @brief Get the control socket path for the specified WPA type. + * + * @param wpaType The type of WPA daemon to get the control socket path for. + * @return constexpr auto The control socket path for the specified WPA type. + */ + static constexpr auto + GetControlSocketPath(WpaType wpaType) + { + switch (wpaType) { + case WpaType::Hostapd: + return ControlSocketPathHostapd; + case WpaType::WpaSupplicant: + return ControlSocketPathWpaSupplicant; + case WpaType::Unknown: + [[fallthrough]]; + default: + return ControlSocketPathBase; + } + } }; } // namespace Wpa diff --git a/tests/unit/linux/wpa-controller/CMakeLists.txt b/tests/unit/linux/wpa-controller/CMakeLists.txt index f3d4c3da..a439a21a 100644 --- a/tests/unit/linux/wpa-controller/CMakeLists.txt +++ b/tests/unit/linux/wpa-controller/CMakeLists.txt @@ -27,8 +27,8 @@ target_link_libraries(wpa-controller-test-unit ) configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/detail/config/hostapd.conf.format.hxx.in - ${CMAKE_CURRENT_BINARY_DIR}/hostapd.conf.format.hxx + ${CMAKE_CURRENT_SOURCE_DIR}/detail/config/HostapdBinaryInfo.hxx.in + ${CMAKE_CURRENT_BINARY_DIR}/HostapdBinaryInfo.hxx @ONLY ) diff --git a/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.cxx b/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.cxx index b730ae7e..fc57b8b5 100644 --- a/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.cxx +++ b/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.cxx @@ -10,15 +10,49 @@ #include #include -#include "WpaDaemonManager.hxx" +#include #include #include #include -#include "hostapd.conf.format.hxx" +#include "HostapdBinaryInfo.hxx" +#include "WpaDaemonManager.hxx" namespace detail { +/** + * @brief Format string for the default wpa_supplicant configuration file contents. + * + * There are 1 arguments expected to be substituted into the format string: + * + * 1. The control interface path. + */ +static constexpr auto WpaDaemonWpaSupplicantConfigurationFileContentsFormat = R"CONFIG( +ctrl_interface={} +)CONFIG"; + +/** + * @brief Format string for the default hostapd configuration file contents. + * + * There are 2 argumentd expected to be substituted into the format string: + * + * 1. The wlan interface name. + * 2. The control interface path. + */ +static constexpr auto WpaDaemonHostapdConfigurationFileContentsFormat = R"CONFIG( +interface={} +driver=nl80211 +ctrl_interface={} +ssid=wificontrollertest +hw_mode=g +channel=1 +auth_algs=3 +wpa=2 +wpa_passphrase=password +wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256 SAE +wpa_pairwise=TKIP CCMP +rsn_pairwise=CCMP +)CONFIG"; /** * @brief Write the default configuration file contents for the specified wpa @@ -26,45 +60,27 @@ namespace detail * * @param wpaType The type of wpa daemon to write the configuration file for. * @param interfaceName The wlan interface the daemon will be managing. + * @param controlSocketPath The path to the control socket for the daemon. * @param configurationFile The file stream to write the configuration file to. */ void -WriteDefaultConfigurationFileContents(Wpa::WpaType wpaType, std::string_view interfaceName, std::ofstream& configurationFile) +WriteDefaultConfigurationFileContents(Wpa::WpaType wpaType, std::string_view interfaceName, std::string_view controlSocketPath, std::ofstream& configurationFile) { switch (wpaType) { - case Wpa::WpaType::Hostapd: { - configurationFile << std::format(WpaDaemonHostapdConfigurationFileContentsFormat, interfaceName); + case Wpa::WpaType::Hostapd: + configurationFile << std::format(WpaDaemonHostapdConfigurationFileContentsFormat, interfaceName, controlSocketPath); break; - } - default: { + case Wpa::WpaType::WpaSupplicant: + configurationFile << std::format(WpaDaemonWpaSupplicantConfigurationFileContentsFormat, controlSocketPath); + break; + case Wpa::WpaType::Unknown: + [[fallthrough]]; + default: throw std::runtime_error(std::format("Unsupported wpa daemon type '{}'", magic_enum::enum_name(wpaType))); } - } } } // namespace detail -/* static */ -std::filesystem::path -WpaDaemonManager::FindDaemonBinary(Wpa::WpaType wpaType, const std::filesystem::path& searchPath) -{ - using std::filesystem::perms; - - const auto daemon = Wpa::GetWpaTypeDaemonBinaryName(wpaType); - - LOGI << std::format("Searching for hostapd daemon binary '{}' in '{}'\n", daemon, searchPath.c_str()); - - for (const auto& directoryEntry : std::filesystem::recursive_directory_iterator(searchPath)) { - if (directoryEntry.is_regular_file() && directoryEntry.path().filename() == daemon) { - const auto permissions = directoryEntry.status().permissions(); - if ((permissions & (perms::owner_exec | perms::group_exec | perms::others_exec)) != perms::none) { - return directoryEntry.path(); - } - } - } - - return {}; -} - /* static */ std::filesystem::path WpaDaemonManager::CreateAndWriteDefaultConfigurationFile(Wpa::WpaType wpaType, std::string_view interfaceName) @@ -72,10 +88,11 @@ WpaDaemonManager::CreateAndWriteDefaultConfigurationFile(Wpa::WpaType wpaType, s // Determine which daemon to create the configuration file for. const auto daemon = Wpa::GetWpaTypeDaemonBinaryName(wpaType); const auto daemonConfigurationFilePath = std::filesystem::temp_directory_path() / std::format("{}.conf", daemon); + const auto daemonControlSocketPath{ Wpa::ProtocolWpaConfig::GetControlSocketPath(wpaType) }; // Create and write default configuration file contents. std::ofstream daemonConfigurationFile{ daemonConfigurationFilePath, std::ios::out | std::ios::trunc }; - detail::WriteDefaultConfigurationFileContents(wpaType, interfaceName, daemonConfigurationFile); + detail::WriteDefaultConfigurationFileContents(wpaType, interfaceName, daemonControlSocketPath, daemonConfigurationFile); daemonConfigurationFile.flush(); daemonConfigurationFile.close(); @@ -92,6 +109,15 @@ WpaDaemonManager::Start(Wpa::WpaType wpaType, std::string_view interfaceName, co interfaceName = WpaDaemonManager::InterfaceNameDefault; } + // Create the control socket path if it doesn't exist. + const std::filesystem::path controlSocketPath{ Wpa::ProtocolWpaConfig::GetControlSocketPath(wpaType) }; + if (!std::filesystem::exists(controlSocketPath)) { + if (!std::filesystem::create_directories(controlSocketPath)) { + LOGE << std::format("Failed to create control socket path '{}'\n", controlSocketPath.c_str()); + return std::nullopt; + } + } + // Determine which daemon to start and formulate daemon binary arguments. const auto daemon = Wpa::GetWpaTypeDaemonBinaryName(wpaType); const auto* configurationFileArgumentPrefix = (wpaType == Wpa::WpaType::WpaSupplicant) ? "-c" : ""; @@ -147,13 +173,7 @@ WpaDaemonManager::StartDefault(Wpa::WpaType wpaType, std::string_view interfaceN return std::nullopt; } - auto daemonFilePath = FindDaemonBinary(wpaType); - if (daemonFilePath.empty()) { - LOGE << std::format("Failed to find wpa '{}' daemon binary\n", magic_enum::enum_name(wpaType)); - return std::nullopt; - } - - return Start(wpaType, interfaceName, daemonFilePath, configurationFilePath); + return Start(wpaType, interfaceName, detail::HostapdBinaryPath, configurationFilePath); } /* static */ diff --git a/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.hxx b/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.hxx index 03240b31..62abe784 100644 --- a/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.hxx +++ b/tests/unit/linux/wpa-controller/detail/WpaDaemonManager.hxx @@ -36,15 +36,6 @@ struct WpaDaemonManager */ static constexpr auto ControlSocketPathBase{ "/run/" }; - /** - * @brief Attempts to find the binary for the specified wpa daemon type. - * - * @param wpaType The type of wpa daemon to find the binary for. - * @return std::filesystem::path The path to the daemon binary, if found. Otherwise, an empty path. - */ - static std::filesystem::path - FindDaemonBinary(Wpa::WpaType wpaType, const std::filesystem::path& searchPath = std::filesystem::current_path()); - /** * @brief Create and write a default configuration file to disk for the * specified wpa daemon type. The configuration file will be written to the diff --git a/tests/unit/linux/wpa-controller/detail/config/HostapdBinaryInfo.hxx.in b/tests/unit/linux/wpa-controller/detail/config/HostapdBinaryInfo.hxx.in new file mode 100644 index 00000000..ee7bbeb2 --- /dev/null +++ b/tests/unit/linux/wpa-controller/detail/config/HostapdBinaryInfo.hxx.in @@ -0,0 +1,23 @@ + +#ifndef HOSTAPD_BINARY_INFO_HXX +#define HOSTAPD_BINARY_INFO_HXX + +/** + * Note: this is a generated file. Do not attempt to change it as any changes will be lost. + */ +#include + +namespace detail +{ +/** + * @brief The path to hostapd binaries. + */ +static const std::filesystem::path HostapdBinaryDirectory{ "@HOSTAP_BINARY_DIR@" }; + +/** + * @brief The path to the hostapd daemon binary. + */ +static const std::filesystem::path HostapdBinaryPath{ HostapdBinaryDirectory / "hostapd" }; +} // namespace detail + +#endif // HOSTAPD_BINARY_INFO_HXX diff --git a/tests/unit/linux/wpa-controller/detail/config/hostapd.conf.format.hxx.in b/tests/unit/linux/wpa-controller/detail/config/hostapd.conf.format.hxx.in deleted file mode 100644 index ca9cb8f8..00000000 --- a/tests/unit/linux/wpa-controller/detail/config/hostapd.conf.format.hxx.in +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef HOSTAPD_CONF_FORMAT_HXX -#define HOSTAPD_CONF_FORMAT_HXX - -namespace detail -{ -static constexpr auto WpaDaemonHostapdConfigurationFileContentsFormat = R"CONFIG( -interface={} -driver=nl80211 -ctrl_interface=@CMAKE_INSTALL_FULL_RUNSTATEDIR@/hostapd -ssid=wificontrollertest -hw_mode=g -channel=1 -auth_algs=3 -wpa=2 -wpa_passphrase=password -wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256 SAE -wpa_pairwise=TKIP CCMP -rsn_pairwise=CCMP -)CONFIG"; - -} // namespace detail - -#endif // HOSTAPD_CONF_FORMAT_HXX