Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
32
tools/EVerest-main/modules/Misc/Setup/BUILD.bazel
Normal file
32
tools/EVerest-main/modules/Misc/Setup/BUILD.bazel
Normal file
@@ -0,0 +1,32 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
load("//modules:module.bzl", "cc_everest_module")
|
||||
load("//third-party/bazel/toolchains:defs.bzl", "CROSS_TEST_INCOMPATIBLE")
|
||||
|
||||
cc_everest_module(
|
||||
name = "Setup",
|
||||
srcs = glob([
|
||||
"*.cpp",
|
||||
"*.hpp",
|
||||
]),
|
||||
deps = [
|
||||
"//lib/everest/run_application",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "Setup_test",
|
||||
target_compatible_with = CROSS_TEST_INCOMPATIBLE,
|
||||
srcs = glob(
|
||||
[
|
||||
"tests/*.cpp",
|
||||
"tests/*.hpp",
|
||||
"WiFiSetup.*",
|
||||
],
|
||||
),
|
||||
includes = ["."],
|
||||
deps = [
|
||||
"//lib/everest/run_application",
|
||||
"@com_github_nlohmann_json//:json",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
29
tools/EVerest-main/modules/Misc/Setup/CMakeLists.txt
Normal file
29
tools/EVerest-main/modules/Misc/Setup/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"WiFiSetup.cpp"
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
everest::run_application
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
target_compile_features(${MODULE_NAME} PRIVATE cxx_std_17)
|
||||
if(EVEREST_CORE_BUILD_TESTING)
|
||||
include(CTest)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
245
tools/EVerest-main/modules/Misc/Setup/README.md
Normal file
245
tools/EVerest-main/modules/Misc/Setup/README.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Setup module API documentation
|
||||
This module is responsible for setup tasks that might need privileged access, for example wifi configuration.
|
||||
|
||||
If not run as root user, set at least the following capabilities in your EVerest config file: CAP_NET_ADMIN, CAP_NET_RAW, CAP_DAC_OVERRIDE.
|
||||
They will be passed on to the child processes such as wpa_cli etc.
|
||||
|
||||
## Periodically published variables
|
||||
### everest_api/setup/var/supported_setup_features
|
||||
This variable is published periodically and contains a JSON object with the supported features in the following form:
|
||||
```json
|
||||
{
|
||||
"localization": true,
|
||||
"setup_simulation": true,
|
||||
"setup_wifi": true
|
||||
}
|
||||
```
|
||||
|
||||
### everest_api/setup/var/hostname
|
||||
This variable is published periodically and contains the hostname.
|
||||
|
||||
## Commands and variables published in response
|
||||
### everest_api/setup/cmd/scan_wifi
|
||||
If any arbitrary payload is published to this topic a list of available wifi networks is published on the following topic:
|
||||
__everest_api/setup/var/wifi_info__
|
||||
|
||||
with the following payload format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"bssid": "00:11:22:33:44:55",
|
||||
"flags": [
|
||||
"WPA2-PSK-CCMP",
|
||||
"ESS"
|
||||
],
|
||||
"frequency": 2437,
|
||||
"signal_level": -41,
|
||||
"ssid": "Example"
|
||||
},
|
||||
{
|
||||
"bssid": "66:77:88:99:aa:bb",
|
||||
"flags": [
|
||||
"WPA2-PSK-CCMP",
|
||||
"ESS"
|
||||
],
|
||||
"frequency": 5180,
|
||||
"signal_level": -56,
|
||||
"ssid": "Example2"
|
||||
}
|
||||
]
|
||||
```
|
||||
additionally general network device information is published on the following topic:
|
||||
__everest_api/setup/var/network_device_info__
|
||||
|
||||
with the following payload format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"blocked": false,
|
||||
"interface": "wlan0",
|
||||
"ipv4": ["192.0.2.23"],
|
||||
"ipv6": ["2001:db8:0:0:0:0:0:23"],
|
||||
"mac": "00:11:22:33:44:55",
|
||||
"rfkill_id": "0",
|
||||
"wireless": true
|
||||
},
|
||||
{
|
||||
"blocked": false,
|
||||
"interface": "eth0",
|
||||
"ipv4": "192.0.2.42",
|
||||
"ipv6": ["2001:db8:0:0:0:0:0:42"],
|
||||
"mac": "11:22:33:44:55:66",
|
||||
"rfkill_id": "",
|
||||
"wireless": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
additionally the list of configured wifi networks is published to the following topic:
|
||||
__everest_api/setup/var/configured_networks__
|
||||
|
||||
with the following payload format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"connected": true,
|
||||
"interface": "wlan0",
|
||||
"network_id": 0,
|
||||
"signal_level": -56,
|
||||
"ssid": "Example"
|
||||
},
|
||||
{
|
||||
"connected": false,
|
||||
"interface": "wlan0",
|
||||
"network_id": 1,
|
||||
"signal_level": -100,
|
||||
"ssid": "Example2"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/enable_wifi_scanning
|
||||
If any arbitrary payload is published to this topic the list of available wifi networks and general network device information just mentioned is published periodically.
|
||||
|
||||
### everest_api/setup/cmd/disable_wifi_scanning
|
||||
If any arbitrary payload is published to this topic the list of available wifi networks and general network device information stops being periodically published.
|
||||
|
||||
### everest_api/setup/cmd/rfkill_unblock
|
||||
If a rfkill_id is published to this topic the wifi interface with this id will be unblocked.
|
||||
|
||||
### everest_api/setup/cmd/rfkill_block
|
||||
If a rfkill_id is published to this topic the wifi interface with this id will be blocked.
|
||||
|
||||
### everest_api/setup/cmd/list_configured_networks
|
||||
If any arbitrary payload is published to this topic the list of configured wifi networks is published to the following topic:
|
||||
__everest_api/setup/var/configured_networks__
|
||||
|
||||
with the following payload format:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"connected": true,
|
||||
"interface": "wlan0",
|
||||
"network_id": 0,
|
||||
"ssid": "Example"
|
||||
},
|
||||
{
|
||||
"connected": false,
|
||||
"interface": "wlan0",
|
||||
"network_id": 1,
|
||||
"ssid": "Example2"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/add_network
|
||||
To add a wifi network a payload with the following format must be published to this topic:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"ssid": "Example",
|
||||
"psk": "20fcb529dee0aad11b0568f553942850d06e4c4531c0d75b35345d580b300f78"
|
||||
}
|
||||
```
|
||||
The PSK field can represent the passphrase instead using escaped quotes:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"ssid": "Example",
|
||||
"psk": "\"A_valid_passphrase\""
|
||||
}
|
||||
```
|
||||
For open WiFi networks the psk must be an empty string `"psk": ""`.
|
||||
|
||||
For hidden networks an optional item is needed:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"ssid": "Example",
|
||||
"psk": "\"A_valid_passphrase\"",
|
||||
"hidden": true
|
||||
}
|
||||
```
|
||||
When `hidden` is not supplied then it is assumed to be false.
|
||||
|
||||
### everest_api/setup/cmd/enable_network
|
||||
To enable a wifi network a payload with the following format must be published to this topic:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"network_id": 0
|
||||
}
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/disable_network
|
||||
To disable a wifi network a payload with the following format must be published to this topic:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"network_id": 0
|
||||
}
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/select_network
|
||||
To select a wifi network a payload with the following format must be published to this topic:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"network_id": 0
|
||||
}
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/remove_network
|
||||
To remove a wifi network a payload with the following format must be published to this topic:
|
||||
```json
|
||||
{
|
||||
"interface": "wlan0",
|
||||
"network_id": 0
|
||||
}
|
||||
```
|
||||
|
||||
### everest_api/setup/cmd/remove_all_networks
|
||||
If any arbitrary payload is published to this topic all wifi networks will be removed.
|
||||
|
||||
### everest_api/setup/cmd/enable_ap
|
||||
If any arbitrary payload is published to this topic a wireless access point will be enabled on the interface configured in the module config.
|
||||
|
||||
### everest_api/setup/cmd/disable_ap
|
||||
If any arbitrary payload is published to this topic the wireless access point will be disabled.
|
||||
|
||||
### everest_api/setup/cmd/check_online_status
|
||||
If any arbitrary payload is published to this topic a ping will be sent to the host configured in the configuration key "online_check_host". Depending on the success of this ping a status of "online" or "offline" will be reported on the following topic:
|
||||
__everest_api/setup/var/online_status__
|
||||
|
||||
### everest_api/setup/cmd/reboot
|
||||
If any arbitrary payload is published to this topic the system will reboot.
|
||||
|
||||
## Application Info / Localization
|
||||
### everest_api/setup/cmd/set_mode
|
||||
If a mode _private_ or _public_ is published to this topic it will be stored permanently.
|
||||
|
||||
### everest_api/setup/cmd/set_initialized
|
||||
If any arbitrary payload is published to this topic the system will be marked as "initialized" permanently.
|
||||
|
||||
### everest_api/setup/cmd/reset_initialized
|
||||
If any arbitrary payload is published to this topic the system will be marked as "uninitialized" permanently.
|
||||
|
||||
### everest_api/setup/cmd/change_default_language
|
||||
You can set a [three-letter language code](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) to be set as the default language which will be stored permanently.
|
||||
|
||||
### everest_api/setup/cmd/change_current_language
|
||||
You can set a [three-letter language code](https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) to be set as the current language.
|
||||
|
||||
### everest_api/setup/cmd/get_application_info
|
||||
If any arbitrary payload is published to this topic a application info object is published to the following topic:
|
||||
__everest_api/setup/var/application_info__
|
||||
|
||||
with the following payload format:
|
||||
```json
|
||||
{
|
||||
"initialized": true,
|
||||
"mode": "private",
|
||||
"default_language": "eng",
|
||||
"current_language": "ger"
|
||||
}
|
||||
```
|
||||
707
tools/EVerest-main/modules/Misc/Setup/Setup.cpp
Normal file
707
tools/EVerest-main/modules/Misc/Setup/Setup.cpp
Normal file
@@ -0,0 +1,707 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "Setup.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
|
||||
#include <everest/run_application/run_application.hpp>
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
using namespace everest::run_application;
|
||||
|
||||
namespace module {
|
||||
|
||||
// set WifiConfigureClass to the class to use for configuring WiFi
|
||||
typedef WpaCliSetup WifiConfigureClass;
|
||||
|
||||
void to_json(json& j, const NetworkDeviceInfo& k) {
|
||||
j = json::object({{"interface", k.interface},
|
||||
{"wireless", k.wireless},
|
||||
{"blocked", k.blocked},
|
||||
{"rfkill_id", k.rfkill_id},
|
||||
{"ipv4", k.ipv4},
|
||||
{"ipv6", k.ipv6},
|
||||
{"mac", k.mac},
|
||||
{"link_type", k.link_type}});
|
||||
}
|
||||
|
||||
void to_json(json& j, const WifiCredentials& k) {
|
||||
j = json::object({{"interface", k.interface}, {"ssid", k.ssid}, {"psk", k.psk}, {"hidden", k.hidden}});
|
||||
}
|
||||
|
||||
void from_json(const json& j, WifiCredentials& k) {
|
||||
k.interface = j.at("interface");
|
||||
k.ssid = j.at("ssid");
|
||||
k.psk = j.at("psk");
|
||||
k.hidden = false;
|
||||
// optional item
|
||||
auto it = j.find("hidden");
|
||||
if ((it != j.end() && *it)) {
|
||||
k.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& j, const InterfaceAndNetworkId& k) {
|
||||
j = json::object({{"interface", k.interface}, {"network_id", k.network_id}});
|
||||
}
|
||||
void from_json(const json& j, InterfaceAndNetworkId& k) {
|
||||
k.interface = j.at("interface");
|
||||
k.network_id = j.at("network_id");
|
||||
}
|
||||
|
||||
void to_json(json& j, const SupportedSetupFeatures& k) {
|
||||
j = json::object(
|
||||
{{"setup_wifi", k.setup_wifi}, {"localization", k.localization}, {"setup_simulation", k.setup_simulation}});
|
||||
}
|
||||
|
||||
void to_json(json& j, const ApplicationInfo& k) {
|
||||
j = json::object({{"initialized", k.initialized},
|
||||
{"mode", k.mode},
|
||||
{"default_language", k.default_language},
|
||||
{"current_language", k.current_language},
|
||||
{"release_metadata_file", k.release_metadata_file}});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// JSON conversion for WifiConfigureClass types
|
||||
static void to_json(json& j, const WifiConfigureClass::WifiNetworkStatus& k) {
|
||||
j = json::object({{"interface", k.interface},
|
||||
{"network_id", k.network_id},
|
||||
{"ssid", k.ssid},
|
||||
{"connected", k.connected},
|
||||
{"signal_level", k.signal_level}});
|
||||
}
|
||||
|
||||
static void to_json(json& j, const WifiConfigureClass::WifiScan& k) {
|
||||
auto flags_array = json::array();
|
||||
flags_array = k.flags;
|
||||
j = json::object({{"bssid", k.bssid},
|
||||
{"ssid", k.ssid},
|
||||
{"frequency", k.frequency},
|
||||
{"signal_level", k.signal_level},
|
||||
{"flags", flags_array}});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Setup::init() {
|
||||
// Set default locale "C" when no locale is set at all
|
||||
try {
|
||||
std::locale loc("");
|
||||
} catch (const std::runtime_error& e) {
|
||||
setenv("LC_ALL", "C", 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Setup::ready() {
|
||||
this->discover_network_thread = std::thread([this]() {
|
||||
while (true) {
|
||||
if ((this->config.setup_wifi) && (wifi_scan_enabled)) {
|
||||
this->discover_network();
|
||||
}
|
||||
this->publish_hostname();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
}
|
||||
});
|
||||
|
||||
this->publish_application_info_thread = std::thread([this]() {
|
||||
while (true) {
|
||||
this->publish_supported_features();
|
||||
this->publish_application_info();
|
||||
this->publish_ap_state();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
});
|
||||
|
||||
std::string set_mode_cmd = this->cmd_base + "set_mode";
|
||||
this->mqtt.subscribe(set_mode_cmd, [this](const std::string& data) { this->set_mode(data); });
|
||||
|
||||
std::string set_initialized_cmd = this->cmd_base + "set_initialized";
|
||||
this->mqtt.subscribe(set_initialized_cmd, [this](const std::string& data) { this->set_initialized(true); });
|
||||
|
||||
std::string reset_initialized_cmd = this->cmd_base + "reset_initialized";
|
||||
this->mqtt.subscribe(reset_initialized_cmd, [this](const std::string& data) { this->set_initialized(false); });
|
||||
|
||||
std::string change_default_language_cmd = this->cmd_base + "change_default_language";
|
||||
this->mqtt.subscribe(change_default_language_cmd,
|
||||
[this](const std::string& data) { this->set_default_language(data); });
|
||||
|
||||
std::string change_current_language_cmd = this->cmd_base + "change_current_language";
|
||||
this->mqtt.subscribe(change_current_language_cmd,
|
||||
[this](const std::string& data) { this->set_current_language(data); });
|
||||
|
||||
std::string get_application_info_cmd = this->cmd_base + "get_application_info";
|
||||
this->mqtt.subscribe(get_application_info_cmd,
|
||||
[this](const std::string& data) { this->publish_application_info(); });
|
||||
|
||||
if (this->config.setup_wifi) {
|
||||
std::string rfkill_unblock_cmd = this->cmd_base + "rfkill_unblock";
|
||||
this->mqtt.subscribe(rfkill_unblock_cmd, [this](const std::string& data) { this->rfkill_unblock(data); });
|
||||
|
||||
std::string rfkill_block_cmd = this->cmd_base + "rfkill_block";
|
||||
this->mqtt.subscribe(rfkill_block_cmd, [this](const std::string& data) { this->rfkill_block(data); });
|
||||
|
||||
std::string list_configured_networks_cmd = this->cmd_base + "list_configured_networks";
|
||||
this->mqtt.subscribe(list_configured_networks_cmd,
|
||||
[this](const std::string& data) { this->publish_configured_networks(); });
|
||||
|
||||
std::string add_network_cmd = this->cmd_base + "add_network";
|
||||
this->mqtt.subscribe(add_network_cmd, [this](const std::string& data) {
|
||||
WifiCredentials wifi_credentials = json::parse(data);
|
||||
WifiConfigureClass wifi;
|
||||
this->add_and_enable_network(wifi_credentials.interface, wifi_credentials.ssid, wifi_credentials.psk,
|
||||
wifi_credentials.hidden);
|
||||
wifi.save_config(wifi_credentials.interface);
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string enable_network_cmd = this->cmd_base + "enable_network";
|
||||
this->mqtt.subscribe(enable_network_cmd, [this](const std::string& data) {
|
||||
InterfaceAndNetworkId wifi_details = json::parse(data);
|
||||
WifiConfigureClass wifi;
|
||||
wifi.enable_network(wifi_details.interface, wifi_details.network_id);
|
||||
wifi.save_config(wifi_details.interface);
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string disable_network_cmd = this->cmd_base + "disable_network";
|
||||
this->mqtt.subscribe(disable_network_cmd, [this](const std::string& data) {
|
||||
InterfaceAndNetworkId wifi_details = json::parse(data);
|
||||
WifiConfigureClass wifi;
|
||||
wifi.disable_network(wifi_details.interface, wifi_details.network_id);
|
||||
wifi.save_config(wifi_details.interface);
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string select_network_cmd = this->cmd_base + "select_network";
|
||||
this->mqtt.subscribe(select_network_cmd, [this](const std::string& data) {
|
||||
InterfaceAndNetworkId wifi_details = json::parse(data);
|
||||
WifiConfigureClass wifi;
|
||||
wifi.select_network(wifi_details.interface, wifi_details.network_id);
|
||||
wifi.save_config(wifi_details.interface);
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string remove_network_cmd = this->cmd_base + "remove_network";
|
||||
this->mqtt.subscribe(remove_network_cmd, [this](const std::string& data) {
|
||||
InterfaceAndNetworkId wifi_details = json::parse(data);
|
||||
WifiConfigureClass wifi;
|
||||
wifi.remove_network(wifi_details.interface, wifi_details.network_id);
|
||||
wifi.save_config(wifi_details.interface);
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string scan_wifi_cmd = this->cmd_base + "scan_wifi";
|
||||
this->mqtt.subscribe(scan_wifi_cmd, [this](const std::string& data) { this->discover_network(); });
|
||||
|
||||
std::string enable_wifi_scanning_cmd = this->cmd_base + "enable_wifi_scanning";
|
||||
this->mqtt.subscribe(enable_wifi_scanning_cmd,
|
||||
[this](const std::string& data) { this->wifi_scan_enabled = true; });
|
||||
|
||||
std::string disable_wifi_scanning_cmd = this->cmd_base + "disable_wifi_scanning";
|
||||
this->mqtt.subscribe(disable_wifi_scanning_cmd,
|
||||
[this](const std::string& data) { this->wifi_scan_enabled = false; });
|
||||
|
||||
std::string remove_all_networks_cmd = this->cmd_base + "remove_all_networks";
|
||||
this->mqtt.subscribe(remove_all_networks_cmd, [this](const std::string& data) {
|
||||
this->remove_all_networks();
|
||||
this->publish_configured_networks();
|
||||
});
|
||||
|
||||
std::string reboot_cmd = this->cmd_base + "reboot";
|
||||
this->mqtt.subscribe(reboot_cmd, [this](const std::string& data) { this->reboot(); });
|
||||
|
||||
std::string check_online_status_cmd = this->cmd_base + "check_online_status";
|
||||
this->mqtt.subscribe(check_online_status_cmd, [this](const std::string& data) { this->check_online_status(); });
|
||||
|
||||
std::string enable_ap_cmd = this->cmd_base + "enable_ap";
|
||||
this->mqtt.subscribe(enable_ap_cmd, [this](const std::string& data) { enable_ap(); });
|
||||
|
||||
std::string disable_ap_cmd = this->cmd_base + "disable_ap";
|
||||
this->mqtt.subscribe(disable_ap_cmd, [this](const std::string& data) { disable_ap(); });
|
||||
}
|
||||
}
|
||||
|
||||
void Setup::publish_supported_features() {
|
||||
SupportedSetupFeatures supported_setup_features;
|
||||
supported_setup_features.setup_wifi = this->config.setup_wifi;
|
||||
supported_setup_features.localization = this->config.localization;
|
||||
supported_setup_features.setup_simulation = this->config.setup_simulation;
|
||||
|
||||
std::string supported_setup_features_var = this->var_base + "supported_setup_features";
|
||||
|
||||
json supported_setup_features_json = supported_setup_features;
|
||||
|
||||
this->mqtt.publish(supported_setup_features_var, supported_setup_features_json.dump());
|
||||
}
|
||||
|
||||
void Setup::publish_application_info() {
|
||||
ApplicationInfo application_info;
|
||||
application_info.initialized = this->get_initialized();
|
||||
application_info.mode = this->get_mode();
|
||||
application_info.default_language = this->get_default_language();
|
||||
application_info.current_language = this->get_current_language();
|
||||
application_info.release_metadata_file = this->info.paths.etc / this->config.release_metadata_file;
|
||||
|
||||
std::string application_info_var = this->var_base + "application_info";
|
||||
|
||||
json application_info_json = application_info;
|
||||
|
||||
this->mqtt.publish(application_info_var, application_info_json.dump());
|
||||
}
|
||||
|
||||
void Setup::publish_hostname() {
|
||||
std::string hostname_var = this->var_base + "hostname";
|
||||
|
||||
this->mqtt.publish(hostname_var, this->get_hostname());
|
||||
}
|
||||
|
||||
void Setup::publish_ap_state() {
|
||||
std::string ap_state_var = this->var_base + "ap_state";
|
||||
|
||||
auto hostapd_enabled_output = run_application("systemctl", {"is-active", "--quiet", "hostapd"});
|
||||
if (hostapd_enabled_output.exit_code == 0) {
|
||||
this->ap_state = "enabled";
|
||||
} else {
|
||||
this->ap_state = "disabled";
|
||||
}
|
||||
|
||||
this->mqtt.publish(ap_state_var, this->ap_state);
|
||||
}
|
||||
|
||||
void Setup::set_default_language(std::string language) {
|
||||
this->r_store->call_store("everest_localization_default_language", language);
|
||||
}
|
||||
|
||||
std::string Setup::get_default_language() {
|
||||
auto language = this->r_store->call_load("everest_localization_default_language");
|
||||
if (!std::holds_alternative<std::string>(language)) {
|
||||
return "unknown";
|
||||
}
|
||||
return std::get<std::string>(language);
|
||||
}
|
||||
|
||||
void Setup::set_current_language(const std::string& language) {
|
||||
this->current_language = language;
|
||||
}
|
||||
|
||||
std::string Setup::get_current_language() {
|
||||
if (this->current_language.empty()) {
|
||||
this->current_language = this->get_default_language();
|
||||
}
|
||||
|
||||
return this->current_language;
|
||||
}
|
||||
|
||||
void Setup::set_mode(std::string mode) {
|
||||
this->r_store->call_store("everest_mode", mode);
|
||||
}
|
||||
|
||||
std::string Setup::get_mode() {
|
||||
auto mode = this->r_store->call_load("everest_mode");
|
||||
if (!std::holds_alternative<std::string>(mode)) {
|
||||
return "unknown";
|
||||
}
|
||||
return std::get<std::string>(mode);
|
||||
}
|
||||
|
||||
void Setup::set_initialized(bool initialized) {
|
||||
this->r_store->call_store("everest_initialized", initialized);
|
||||
}
|
||||
|
||||
bool Setup::get_initialized() {
|
||||
if (this->config.initialized_by_default) {
|
||||
return true;
|
||||
}
|
||||
auto initialized = this->r_store->call_load("everest_initialized");
|
||||
if (!std::holds_alternative<bool>(initialized)) {
|
||||
return false;
|
||||
}
|
||||
return std::get<bool>(initialized);
|
||||
}
|
||||
|
||||
void Setup::discover_network() {
|
||||
std::vector<NetworkDeviceInfo> device_info = this->get_network_devices();
|
||||
|
||||
this->populate_rfkill_status(device_info);
|
||||
this->populate_ip_addresses(device_info);
|
||||
|
||||
std::string network_device_info_var = this->var_base + "network_device_info";
|
||||
json device_info_json = json::array();
|
||||
device_info_json = device_info;
|
||||
this->mqtt.publish(network_device_info_var, device_info_json.dump());
|
||||
|
||||
auto wifi_info = this->scan_wifi(device_info);
|
||||
|
||||
std::string wifi_info_var = this->var_base + "wifi_info";
|
||||
json wifi_info_json = json::array();
|
||||
wifi_info_json = wifi_info;
|
||||
this->mqtt.publish(wifi_info_var, wifi_info_json.dump());
|
||||
|
||||
this->publish_configured_networks();
|
||||
}
|
||||
|
||||
std::string Setup::read_type_file(const fs::path& type_path) {
|
||||
if (!fs::exists(type_path)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::ifstream ifs(type_path.c_str());
|
||||
std::string type_file((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
// trim newlines
|
||||
type_file.erase(std::remove(type_file.begin(), type_file.end(), '\n'), type_file.end());
|
||||
|
||||
return type_file;
|
||||
}
|
||||
|
||||
std::vector<NetworkDeviceInfo> Setup::get_network_devices() {
|
||||
auto sys_net_path = fs::path("/sys/class/net");
|
||||
auto sys_virtual_net_path = fs::path("/sys/devices/virtual/net");
|
||||
|
||||
std::vector<NetworkDeviceInfo> device_info;
|
||||
|
||||
for (auto&& net_it : fs::directory_iterator(sys_net_path)) {
|
||||
auto net_path = net_it.path();
|
||||
auto type_path = net_path / "type";
|
||||
if (!fs::exists(type_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string type_file = this->read_type_file(type_path);
|
||||
|
||||
auto interface = net_path.filename();
|
||||
auto virtual_interface = sys_virtual_net_path / interface;
|
||||
|
||||
// check if type is ethernet:
|
||||
if (type_file == "1") {
|
||||
if (fs::exists(virtual_interface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto device = NetworkDeviceInfo();
|
||||
device.interface = interface.string();
|
||||
device.link_type = "ether";
|
||||
|
||||
// check if its wireless or not:
|
||||
auto wireless_path = net_path / "wireless";
|
||||
if (fs::exists(wireless_path)) {
|
||||
device.wireless = true;
|
||||
auto phy80211_path = net_path / "phy80211";
|
||||
for (auto&& rfkill_it : fs::directory_iterator(phy80211_path)) {
|
||||
auto phy_file_path = rfkill_it.path().filename().string();
|
||||
std::string rfkill = "rfkill";
|
||||
if (phy_file_path.find(rfkill) == 0) {
|
||||
phy_file_path.erase(0, rfkill.size());
|
||||
device.rfkill_id = phy_file_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_info.push_back(device);
|
||||
} else if (type_file == "65534") {
|
||||
if (!fs::exists(virtual_interface)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto virtual_type_path = virtual_interface / "type";
|
||||
|
||||
if (!fs::exists(virtual_type_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string virtual_type_file = this->read_type_file(virtual_type_path);
|
||||
if (virtual_type_file == type_file) {
|
||||
// assume it's a vpn, but check ip link
|
||||
auto ip_output = run_application("ip", {"--json", "-details", "link", "show", interface});
|
||||
if (ip_output.exit_code != 0) {
|
||||
continue;
|
||||
}
|
||||
const auto ip_json = json::parse(ip_output.output);
|
||||
if (ip_json.size() < 1) {
|
||||
continue;
|
||||
}
|
||||
const auto& entry = ip_json.at(0);
|
||||
if (entry.contains("linkinfo") and entry.at("linkinfo").contains("info_kind")) {
|
||||
auto device = NetworkDeviceInfo();
|
||||
device.interface = interface.string();
|
||||
device.link_type = entry.at("linkinfo").at("info_kind");
|
||||
device_info.push_back(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return device_info;
|
||||
}
|
||||
|
||||
void Setup::populate_rfkill_status(std::vector<NetworkDeviceInfo>& device_info) {
|
||||
auto rfkill_output = run_application("rfkill", {"--json"});
|
||||
if (rfkill_output.exit_code != 0) {
|
||||
return;
|
||||
}
|
||||
auto rfkill_json = json::parse(rfkill_output.output);
|
||||
for (auto rfkill_object : rfkill_json.items()) {
|
||||
for (auto rfkill_device : rfkill_object.value()) {
|
||||
for (auto& device : device_info) {
|
||||
int device_id = rfkill_device.at("id");
|
||||
if (!device.rfkill_id.empty() && std::to_string(device_id) == device.rfkill_id) {
|
||||
if (rfkill_device.at("soft") == "blocked") {
|
||||
device.blocked = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Setup::rfkill_unblock(std::string rfkill_id) {
|
||||
auto network_devices = this->get_network_devices();
|
||||
this->populate_rfkill_status(network_devices);
|
||||
bool found = false;
|
||||
for (auto device : network_devices) {
|
||||
if (device.rfkill_id == rfkill_id) {
|
||||
if (!device.blocked) {
|
||||
return true;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rfkill_output = run_application("rfkill", {"unblock", rfkill_id});
|
||||
if (rfkill_output.exit_code != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Setup::rfkill_block(std::string rfkill_id) {
|
||||
auto network_devices = this->get_network_devices();
|
||||
this->populate_rfkill_status(network_devices);
|
||||
bool found = false;
|
||||
for (auto device : network_devices) {
|
||||
if (device.rfkill_id == rfkill_id) {
|
||||
if (device.blocked) {
|
||||
return true;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rfkill_output = run_application("rfkill", {"block", rfkill_id});
|
||||
if (rfkill_output.exit_code != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Setup::publish_configured_networks() {
|
||||
auto network_devices = this->get_network_devices();
|
||||
|
||||
WpaCliSetup::WifiNetworkStatusList all_wifi_networks;
|
||||
|
||||
for (auto device : network_devices) {
|
||||
if (!device.wireless) {
|
||||
continue;
|
||||
}
|
||||
WifiConfigureClass wifi;
|
||||
auto network_list = wifi.list_networks_status(device.interface);
|
||||
for (auto& i : network_list) {
|
||||
all_wifi_networks.push_back(std::move(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::string network_list_var = this->var_base + "configured_networks";
|
||||
json configured_networks_json = json::array();
|
||||
configured_networks_json = all_wifi_networks;
|
||||
this->mqtt.publish(network_list_var, configured_networks_json.dump());
|
||||
}
|
||||
|
||||
bool Setup::add_and_enable_network(const std::string& interface, const std::string& ssid, const std::string& psk,
|
||||
bool hidden) {
|
||||
WifiConfigureClass wifi;
|
||||
|
||||
std::string net_if = interface;
|
||||
if (net_if.empty()) {
|
||||
EVLOG_warning << "Attempting to add a network without an interface, attempting to use the first one";
|
||||
auto network_devices = this->get_network_devices();
|
||||
for (auto device : network_devices) {
|
||||
if (device.wireless) {
|
||||
net_if = device.interface;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto network_id = wifi.add_network(net_if);
|
||||
bool bResult = network_id != -1;
|
||||
bResult = bResult && wifi.set_network(net_if, network_id, ssid, psk, hidden);
|
||||
bResult = bResult && wifi.enable_network(net_if, network_id);
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool Setup::remove_all_networks() {
|
||||
auto network_devices = this->get_network_devices();
|
||||
std::uint32_t remove_fail = 0;
|
||||
|
||||
for (auto device : network_devices) {
|
||||
if (!device.wireless) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WifiConfigureClass wifi;
|
||||
auto networks = wifi.list_networks(device.interface);
|
||||
|
||||
for (auto network : networks) {
|
||||
if (!wifi.remove_network(device.interface, network.network_id)) {
|
||||
remove_fail++;
|
||||
}
|
||||
}
|
||||
|
||||
wifi.save_config(device.interface);
|
||||
}
|
||||
|
||||
return remove_fail == 0;
|
||||
}
|
||||
|
||||
bool Setup::reboot() {
|
||||
bool success = true;
|
||||
auto reboot_output = run_application("systemctl", {"reboot"});
|
||||
if (reboot_output.exit_code != 0) {
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Setup::is_online() {
|
||||
bool success = true;
|
||||
auto reboot_output = run_application("ping", {"-c", "1", this->config.online_check_host});
|
||||
if (reboot_output.exit_code != 0) {
|
||||
success = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void Setup::check_online_status() {
|
||||
std::string online_status_var = this->var_base + "online_status";
|
||||
|
||||
if (this->is_online()) {
|
||||
this->mqtt.publish(online_status_var, "online");
|
||||
} else {
|
||||
this->mqtt.publish(online_status_var, "offline");
|
||||
}
|
||||
}
|
||||
|
||||
void Setup::enable_ap() {
|
||||
auto wpa_cli_output = run_application("wpa_cli", {"-i", this->config.ap_interface, "disconnect"});
|
||||
if (wpa_cli_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not disconnect from wireless LAN";
|
||||
}
|
||||
auto start_hostapd_output = run_application("systemctl", {"start", "hostapd"});
|
||||
if (start_hostapd_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not start hostapd";
|
||||
}
|
||||
auto start_dnsmasq_output = run_application("systemctl", {"start", "dnsmasq"});
|
||||
if (start_dnsmasq_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not start dnsmasq";
|
||||
}
|
||||
auto add_static_ip_output =
|
||||
run_application("ip", {"addr", "add", this->config.ap_ipv4, "dev", this->config.ap_interface});
|
||||
if (add_static_ip_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not add static ip to interface " << this->config.ap_interface;
|
||||
}
|
||||
}
|
||||
|
||||
void Setup::disable_ap() {
|
||||
auto del_static_ip_output =
|
||||
run_application("ip", {"addr", "del", this->config.ap_ipv4, "dev", this->config.ap_interface});
|
||||
if (del_static_ip_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not del static ip " << this->config.ap_ipv4 << " from interface "
|
||||
<< this->config.ap_interface;
|
||||
}
|
||||
auto stop_dnsmasq_output = run_application("systemctl", {"stop", "dnsmasq"});
|
||||
if (stop_dnsmasq_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not stop dnsmasq";
|
||||
}
|
||||
auto stop_hostapd_output = run_application("systemctl", {"stop", "hostapd"});
|
||||
if (stop_hostapd_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not stop hostapd";
|
||||
}
|
||||
|
||||
auto wpa_cli_output = run_application("wpa_cli", {"-i", this->config.ap_interface, "reconnect"});
|
||||
if (wpa_cli_output.exit_code != 0) {
|
||||
EVLOG_error << "Could not reconnect to wireless LAN";
|
||||
}
|
||||
}
|
||||
|
||||
static void add_addr_infos_to_device(const json& addr_infos, NetworkDeviceInfo& device) {
|
||||
for (const auto& addr_info : addr_infos) {
|
||||
if (addr_info.at("family") == "inet") {
|
||||
device.ipv4.push_back(addr_info.at("local"));
|
||||
} else if (addr_info.at("family") == "inet6") {
|
||||
device.ipv6.push_back(addr_info.at("local"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Setup::populate_ip_addresses(std::vector<NetworkDeviceInfo>& device_info) {
|
||||
auto ip_output = run_application("ip", {"--json", "address", "show"});
|
||||
if (ip_output.exit_code != 0) {
|
||||
return;
|
||||
}
|
||||
const auto ip_json = json::parse(ip_output.output);
|
||||
for (const auto& ip_object : ip_json) {
|
||||
const std::string ifname = ip_object.at("ifname");
|
||||
auto device = std::find_if(device_info.begin(), device_info.end(),
|
||||
[&ifname](NetworkDeviceInfo& device) { return device.interface == ifname; });
|
||||
if (device == device_info.end()) {
|
||||
continue;
|
||||
}
|
||||
if (ip_object.contains("address")) {
|
||||
device->mac = ip_object.at("address");
|
||||
}
|
||||
add_addr_infos_to_device(ip_object.at("addr_info"), *device);
|
||||
}
|
||||
}
|
||||
|
||||
WifiConfigureClass::WifiScanList Setup::scan_wifi(const std::vector<NetworkDeviceInfo>& device_info) {
|
||||
WifiConfigureClass::WifiScanList wifi_info;
|
||||
WifiConfigureClass wifi;
|
||||
|
||||
for (auto device : device_info) {
|
||||
if (!device.wireless) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto dev_list = wifi.scan_wifi(device.interface);
|
||||
wifi_info.insert(wifi_info.end(), dev_list.begin(), dev_list.end());
|
||||
}
|
||||
|
||||
return wifi_info;
|
||||
}
|
||||
|
||||
std::string Setup::get_hostname() {
|
||||
auto hostname_output = run_application("hostname", {});
|
||||
if (hostname_output.exit_code == 0 && hostname_output.split_output.size() > 0) {
|
||||
return hostname_output.split_output.at(0);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
189
tools/EVerest-main/modules/Misc/Setup/Setup.hpp
Normal file
189
tools/EVerest-main/modules/Misc/Setup/Setup.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef SETUP_HPP
|
||||
#define SETUP_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/kvs/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
#include "WiFiSetup.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace module {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct WifiCredentials {
|
||||
std::string interface;
|
||||
std::string ssid;
|
||||
std::string psk;
|
||||
bool hidden;
|
||||
|
||||
operator std::string() {
|
||||
|
||||
json wifi_credentials = *this;
|
||||
|
||||
return wifi_credentials.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const WifiCredentials& k);
|
||||
void from_json(const json& j, WifiCredentials& k);
|
||||
|
||||
struct InterfaceAndNetworkId {
|
||||
std::string interface;
|
||||
int network_id;
|
||||
|
||||
operator std::string() {
|
||||
json remove_wifi = *this;
|
||||
|
||||
return remove_wifi.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const InterfaceAndNetworkId& k);
|
||||
void from_json(const json& j, InterfaceAndNetworkId& k);
|
||||
|
||||
struct NetworkDeviceInfo {
|
||||
std::string interface;
|
||||
bool wireless = false;
|
||||
bool blocked = false;
|
||||
std::string rfkill_id;
|
||||
std::vector<std::string> ipv4;
|
||||
std::vector<std::string> ipv6;
|
||||
std::string mac;
|
||||
std::string link_type;
|
||||
|
||||
operator std::string() {
|
||||
json device_info = *this;
|
||||
|
||||
return device_info.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const NetworkDeviceInfo& k);
|
||||
|
||||
struct SupportedSetupFeatures {
|
||||
bool setup_wifi;
|
||||
bool localization;
|
||||
bool setup_simulation;
|
||||
|
||||
operator std::string() {
|
||||
json supported_setup_features = *this;
|
||||
|
||||
return supported_setup_features.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const SupportedSetupFeatures& k);
|
||||
|
||||
struct ApplicationInfo {
|
||||
bool initialized;
|
||||
std::string mode;
|
||||
std::string default_language;
|
||||
std::string current_language;
|
||||
std::string release_metadata_file;
|
||||
|
||||
operator std::string() {
|
||||
json application_info = *this;
|
||||
|
||||
return application_info.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const ApplicationInfo& k);
|
||||
} // namespace module
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
bool setup_wifi;
|
||||
bool localization;
|
||||
bool setup_simulation;
|
||||
std::string online_check_host;
|
||||
bool initialized_by_default;
|
||||
std::string release_metadata_file;
|
||||
std::string ap_interface;
|
||||
std::string ap_ipv4;
|
||||
};
|
||||
|
||||
class Setup : public Everest::ModuleBase {
|
||||
public:
|
||||
Setup() = delete;
|
||||
Setup(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, std::unique_ptr<kvsIntf> r_store,
|
||||
Conf& config) :
|
||||
ModuleBase(info), mqtt(mqtt_provider), r_store(std::move(r_store)), config(config){};
|
||||
|
||||
Everest::MqttProvider& mqtt;
|
||||
const std::unique_ptr<kvsIntf> r_store;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::string api_base = "everest_api/setup/";
|
||||
std::string var_base = api_base + "var/";
|
||||
std::string cmd_base = api_base + "cmd/";
|
||||
std::thread discover_network_thread;
|
||||
std::thread publish_application_info_thread;
|
||||
bool wifi_scan_enabled = false;
|
||||
std::string ap_state = "unknown";
|
||||
void publish_supported_features();
|
||||
void publish_application_info();
|
||||
void publish_hostname();
|
||||
void publish_ap_state();
|
||||
void set_default_language(std::string language);
|
||||
std::string get_default_language();
|
||||
std::string current_language;
|
||||
void set_current_language(const std::string& language);
|
||||
std::string get_current_language();
|
||||
void set_mode(std::string mode);
|
||||
std::string get_mode();
|
||||
void set_initialized(bool initialized);
|
||||
bool get_initialized();
|
||||
void discover_network();
|
||||
std::string read_type_file(const fs::path& type_path);
|
||||
std::vector<NetworkDeviceInfo> get_network_devices();
|
||||
void populate_rfkill_status(std::vector<NetworkDeviceInfo>& device_info);
|
||||
bool rfkill_unblock(std::string rfkill_id);
|
||||
bool rfkill_block(std::string rfkill_id);
|
||||
|
||||
void publish_configured_networks();
|
||||
bool add_and_enable_network(const std::string& interface, const std::string& ssid, const std::string& psk,
|
||||
bool hidden = false);
|
||||
bool remove_all_networks();
|
||||
bool reboot();
|
||||
bool is_online();
|
||||
void check_online_status();
|
||||
void enable_ap();
|
||||
void disable_ap();
|
||||
void populate_ip_addresses(std::vector<NetworkDeviceInfo>& device_info);
|
||||
WpaCliSetup::WifiScanList scan_wifi(const std::vector<NetworkDeviceInfo>& device_info);
|
||||
std::string get_hostname();
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // SETUP_HPP
|
||||
578
tools/EVerest-main/modules/Misc/Setup/WiFiSetup.cpp
Normal file
578
tools/EVerest-main/modules/Misc/Setup/WiFiSetup.cpp
Normal file
@@ -0,0 +1,578 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "WiFiSetup.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <everest/run_application/run_application.hpp>
|
||||
|
||||
using namespace everest::run_application;
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief wpa_cli command failure detection
|
||||
*
|
||||
* `wpa_cli` sets an exit code of 0 unless the command is malformed.
|
||||
* Failures are presented via text to stdout.
|
||||
* Hence checking for failure to remove a network would mean checking
|
||||
* the output for OK or FAIL.
|
||||
*
|
||||
* This is common across all calls to `wpa_cli`.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
inline int hex_digit_to_nibble(std::uint8_t c) {
|
||||
int result{-1};
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
result = static_cast<std::uint8_t>(c - '0');
|
||||
} else if ((c >= 'a') && (c <= 'f')) {
|
||||
result = static_cast<std::uint8_t>(c - 'a') + 10;
|
||||
} else if ((c >= 'A') && (c <= 'F')) {
|
||||
result = static_cast<std::uint8_t>(c - 'A') + 10;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline int hex_to_int(std::uint8_t high, std::uint8_t low) {
|
||||
int result{-1};
|
||||
const auto h = hex_digit_to_nibble(high);
|
||||
const auto l = hex_digit_to_nibble(low);
|
||||
if ((h != -1) && (l != -1)) {
|
||||
const auto hc = static_cast<std::uint8_t>(h) << 4U;
|
||||
const auto lc = static_cast<std::uint8_t>(l);
|
||||
result = static_cast<int>(hc | lc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::uint8_t nibble_to_hex_digit(std::uint8_t c) {
|
||||
std::uint8_t result{};
|
||||
c &= 0x0fU;
|
||||
if (c <= 9) {
|
||||
result = c + '0';
|
||||
} else {
|
||||
result = (c - 10) + 'a';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void int_to_hex(std::uint8_t& high, std::uint8_t& low, std::uint8_t c) {
|
||||
high = nibble_to_hex_digit(c >> 4U);
|
||||
low = nibble_to_hex_digit(c);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace module {
|
||||
|
||||
constexpr const char* wpa_cli = "/usr/sbin/wpa_cli";
|
||||
constexpr const int not_connected_rssi = -100; // -100 dBm is the minimum for wifi
|
||||
|
||||
bool WpaCliSetup::do_scan(const std::string& interface) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "scan"});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
WpaCliSetup::WifiScanList WpaCliSetup::do_scan_results(const std::string& interface) {
|
||||
WifiScanList result = {};
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "scan_results"});
|
||||
if (output.exit_code == 0) {
|
||||
auto scan_results = output.split_output;
|
||||
if (scan_results.size() >= 2) {
|
||||
// skip header
|
||||
for (auto scan_results_it = std::next(scan_results.begin()); scan_results_it != scan_results.end();
|
||||
++scan_results_it) {
|
||||
|
||||
std::vector<std::string> columns;
|
||||
std::istringstream stream(*scan_results_it);
|
||||
for (std::string value; std::getline(stream, value, '\t');) {
|
||||
columns.push_back(std::move(value));
|
||||
}
|
||||
|
||||
if (columns.size() >= 5) {
|
||||
WifiScan info;
|
||||
info.bssid = columns[0];
|
||||
info.ssid = columns[4];
|
||||
info.frequency = std::stoi(columns[1]);
|
||||
info.signal_level = std::stoi(columns[2]);
|
||||
info.flags = std::move(parse_flags(columns[3]));
|
||||
result.push_back(std::move(info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WpaCliSetup::Status WpaCliSetup::do_status(const std::string& interface) {
|
||||
Status result = {};
|
||||
if (is_wifi_interface(interface)) {
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "status"});
|
||||
if (output.exit_code == 0) {
|
||||
auto scan_results = output.split_output;
|
||||
for (auto& scan_result : scan_results) {
|
||||
std::vector<std::string> columns;
|
||||
std::istringstream ss(scan_result);
|
||||
for (std::string value; std::getline(ss, value, '=');) {
|
||||
columns.push_back(std::move(value));
|
||||
}
|
||||
|
||||
if (columns.size() == 2) {
|
||||
result[columns[0]] = columns[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WpaCliSetup::Poll WpaCliSetup::do_signal_poll(const std::string& interface) {
|
||||
Poll result = {};
|
||||
if (is_wifi_interface(interface)) {
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "signal_poll"});
|
||||
if (output.exit_code == 0) {
|
||||
auto scan_results = output.split_output;
|
||||
for (auto& scan_result : scan_results) {
|
||||
std::vector<std::string> columns;
|
||||
std::istringstream ss(scan_result);
|
||||
for (std::string value; std::getline(ss, value, '=');) {
|
||||
columns.push_back(std::move(value));
|
||||
}
|
||||
|
||||
if (columns.size() == 2) {
|
||||
result[columns[0]] = columns[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WpaCliSetup::flags_t WpaCliSetup::parse_flags(const std::string& flags) {
|
||||
const std::regex flags_regex("\\[(.*?)\\]");
|
||||
|
||||
flags_t parsed_flags;
|
||||
|
||||
for (auto it = std::sregex_iterator(flags.begin(), flags.end(), flags_regex); it != std::sregex_iterator(); ++it) {
|
||||
parsed_flags.push_back((*it).str(1));
|
||||
}
|
||||
|
||||
return parsed_flags;
|
||||
}
|
||||
|
||||
int WpaCliSetup::add_network(const std::string& interface) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "add_network"});
|
||||
|
||||
if ((output.exit_code != 0) || (output.split_output.size() != 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return std::stoi(output.split_output.at(0));
|
||||
}
|
||||
|
||||
bool WpaCliSetup::set_network(const std::string& interface, int network_id, const std::string& ssid,
|
||||
const std::string& psk, network_security_t mode, bool hidden) {
|
||||
/*
|
||||
* configuring a network needs:
|
||||
* - ssid "<SSID>"
|
||||
* - psk "<Passphrase>" or ABCDEF0123456789... (for WPA2)
|
||||
* - sae_password "<Passphrase>" (for WPA3)
|
||||
* - key_mgmt NONE (for open networks)
|
||||
* - scan_ssid 1 (for hidden networks)
|
||||
*
|
||||
* Support for WPA3 requires:
|
||||
* - key_mgmt WPA-PSK WPA-PSK-SHA256 SAE or SAE if WPA3 only
|
||||
* - sae_password replaces psk, WPA3 doesn't support PreSharedKey (64 hex digits)
|
||||
* the passphrase is required
|
||||
* - for interworking WPA2 and WPA3 the passphrase is needed
|
||||
* - psk with hex digits (PreSharedKey) doesn't work
|
||||
*/
|
||||
|
||||
/*
|
||||
* From wpa_supplicant/hostapd
|
||||
* ieee80211w: Whether management frame protection (MFP) is enabled
|
||||
* 0 = disabled (default)
|
||||
* 1 = optional
|
||||
* 2 = required
|
||||
* The most common configuration options for this based on the PMF (protected
|
||||
* management frames) certification program are:
|
||||
* PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256
|
||||
* PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256
|
||||
* (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used)
|
||||
* WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE
|
||||
*/
|
||||
|
||||
constexpr std::uint8_t wpa2_psk_size = 64U;
|
||||
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (psk.empty()) {
|
||||
// force security mode to none
|
||||
mode = network_security_t::none;
|
||||
}
|
||||
|
||||
const char* key_mgt = nullptr;
|
||||
const char* psk_name = nullptr;
|
||||
const char* ieee80211w = nullptr;
|
||||
|
||||
switch (mode) {
|
||||
case network_security_t::none:
|
||||
key_mgt = "NONE";
|
||||
break;
|
||||
case network_security_t::wpa2_only:
|
||||
key_mgt = "WPA-PSK";
|
||||
psk_name = "psk";
|
||||
break;
|
||||
case network_security_t::wpa3_only:
|
||||
key_mgt = "SAE";
|
||||
psk_name = "sae_password";
|
||||
ieee80211w = "2";
|
||||
break;
|
||||
case network_security_t::wpa2_and_wpa3:
|
||||
default:
|
||||
if (psk.size() == wpa2_psk_size) {
|
||||
// WPA3 doesn't support PSK (hex digits), it needs a passphrase
|
||||
key_mgt = "WPA-PSK";
|
||||
psk_name = "psk";
|
||||
} else if (psk.size() > wpa2_psk_size) {
|
||||
// WPA2 doesn't support passphrases > 63 characters
|
||||
key_mgt = "SAE";
|
||||
psk_name = "sae_password";
|
||||
ieee80211w = "2";
|
||||
} else {
|
||||
key_mgt = "WPA-PSK WPA-PSK-SHA256 SAE";
|
||||
psk_name = "psk";
|
||||
ieee80211w = "1";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
auto network_id_string = std::to_string(network_id);
|
||||
|
||||
// de-escaping SSID strings in wpa_supplicant is not reliable.
|
||||
// hence providing the SSID as a string of hex digits
|
||||
auto ssid_parameter = ssid_to_hex(ssid);
|
||||
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "set_network", network_id_string, "ssid", ssid_parameter});
|
||||
|
||||
if ((output.exit_code == 0) && (psk_name != nullptr)) {
|
||||
output = run_application(wpa_cli, {"-i", interface, "set_network", network_id_string, psk_name, psk});
|
||||
}
|
||||
|
||||
if (output.exit_code == 0) {
|
||||
output = run_application(wpa_cli, {"-i", interface, "set_network", network_id_string, "key_mgmt", key_mgt});
|
||||
}
|
||||
|
||||
if ((output.exit_code == 0) && (ieee80211w != nullptr)) {
|
||||
output =
|
||||
run_application(wpa_cli, {"-i", interface, "set_network", network_id_string, "ieee80211w", ieee80211w});
|
||||
}
|
||||
|
||||
if (hidden && (output.exit_code == 0)) {
|
||||
output = run_application(wpa_cli, {"-i", interface, "set_network", network_id_string, "scan_ssid", "1"});
|
||||
}
|
||||
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::enable_network(const std::string& interface, int network_id) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto network_id_string = std::to_string(network_id);
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "enable_network", network_id_string});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::disable_network(const std::string& interface, int network_id) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto network_id_string = std::to_string(network_id);
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "disable_network", network_id_string});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::select_network(const std::string& interface, int network_id) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto network_id_string = std::to_string(network_id);
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "select_network", network_id_string});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::remove_network(const std::string& interface, int network_id) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto network_id_string = std::to_string(network_id);
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "remove_network", network_id_string});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::save_config(const std::string& interface) {
|
||||
if (!is_wifi_interface(interface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "save_config"});
|
||||
return output.exit_code == 0;
|
||||
}
|
||||
|
||||
WpaCliSetup::WifiScanList WpaCliSetup::scan_wifi(const std::string& interface) {
|
||||
WifiScanList result = {};
|
||||
|
||||
if (do_scan(interface)) {
|
||||
// FIXME: is there a proper signal to check if the scan is ready? Maybe in the socket based interface
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
result = std::move(do_scan_results(interface));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
WpaCliSetup::WifiNetworkList WpaCliSetup::list_networks(const std::string& interface) {
|
||||
WifiNetworkList result = {};
|
||||
if (is_wifi_interface(interface)) {
|
||||
auto output = run_application(wpa_cli, {"-i", interface, "list_networks"});
|
||||
if (output.exit_code == 0) {
|
||||
auto scan_results = output.split_output;
|
||||
if (scan_results.size() >= 2) {
|
||||
// skip header
|
||||
for (auto scan_results_it = std::next(scan_results.begin()); scan_results_it != scan_results.end();
|
||||
++scan_results_it) {
|
||||
|
||||
std::vector<std::string> columns;
|
||||
std::istringstream ss(*scan_results_it);
|
||||
for (std::string value; std::getline(ss, value, '\t');) {
|
||||
columns.push_back(std::move(value));
|
||||
}
|
||||
|
||||
if (columns.size() >= 2) {
|
||||
WifiNetwork info;
|
||||
info.network_id = std::stoi(columns[0]);
|
||||
info.ssid = columns[1];
|
||||
result.push_back(std::move(info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
WpaCliSetup::WifiNetworkStatusList WpaCliSetup::list_networks_status(const std::string& interface) {
|
||||
WifiNetworkStatusList result = {};
|
||||
if (is_wifi_interface(interface)) {
|
||||
auto network_list = list_networks(interface);
|
||||
auto status_map = do_status(interface);
|
||||
int connected_rssi = not_connected_rssi;
|
||||
|
||||
// signal_poll raises errors when not connected
|
||||
if (status_map["wpa_state"] == "COMPLETED") {
|
||||
auto signal_map = do_signal_poll(interface);
|
||||
if (auto it = signal_map.find("RSSI"); it != signal_map.end()) {
|
||||
connected_rssi = std::stoi(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& i : network_list) {
|
||||
WifiNetworkStatus net;
|
||||
net.interface = interface;
|
||||
net.network_id = i.network_id;
|
||||
net.ssid = i.ssid;
|
||||
net.connected = false;
|
||||
net.signal_level = not_connected_rssi;
|
||||
|
||||
auto id_it = status_map.find("id");
|
||||
auto ssid_it = status_map.find("ssid");
|
||||
|
||||
if ((id_it != status_map.end()) && (ssid_it != status_map.end()) &&
|
||||
(std::stoi(id_it->second) == i.network_id) && (ssid_it->second == i.ssid)) {
|
||||
net.connected = true;
|
||||
net.signal_level = connected_rssi;
|
||||
}
|
||||
result.push_back(net);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WpaCliSetup::is_wifi_interface(const std::string& interface) {
|
||||
// check if /sys/class/net/<interface>/wireless exists
|
||||
|
||||
auto path = std::filesystem::path("/sys/class/net");
|
||||
path /= interface;
|
||||
path /= "wireless";
|
||||
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
int Ssid::standard(std::uint8_t c) {
|
||||
int output{-1};
|
||||
if (c == '\\') {
|
||||
handler = &Ssid::backslash;
|
||||
} else {
|
||||
output = static_cast<int>(c);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
int Ssid::backslash(std::uint8_t c) {
|
||||
int output{static_cast<int>(c)};
|
||||
handler = &Ssid::standard;
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\\':
|
||||
break;
|
||||
case 'n':
|
||||
output = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
output = '\r';
|
||||
break;
|
||||
case 't':
|
||||
output = '\t';
|
||||
break;
|
||||
case 'e':
|
||||
output = '\033';
|
||||
break;
|
||||
case 'x':
|
||||
handler = &Ssid::hex_1;
|
||||
output = -1;
|
||||
break;
|
||||
default:
|
||||
// malformed
|
||||
error = true;
|
||||
output = -1;
|
||||
break;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
int Ssid::hex_1(std::uint8_t c) {
|
||||
tmp = static_cast<std::uint8_t>(c);
|
||||
handler = &Ssid::hex_2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Ssid::hex_2(std::uint8_t c) {
|
||||
int output{-1};
|
||||
handler = &Ssid::standard;
|
||||
const auto res = hex_to_int(tmp, c);
|
||||
if (res != -1) {
|
||||
output = res;
|
||||
} else {
|
||||
error = true;
|
||||
// malformed
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string Ssid::to_hex(const std::string& ssid) {
|
||||
std::ostringstream ss;
|
||||
handler = &Ssid::standard;
|
||||
error = false;
|
||||
|
||||
for (const auto& c : ssid) {
|
||||
const auto output = std::invoke(handler, this, static_cast<std::uint8_t>(c));
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
if (output != -1) {
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << output;
|
||||
}
|
||||
}
|
||||
return (error) ? std::string{} : ss.str();
|
||||
}
|
||||
|
||||
void Ssid::encode(int c, std::ostringstream& ss) {
|
||||
if ((c < 0) || (c > 255)) {
|
||||
error = true;
|
||||
} else {
|
||||
switch (c) {
|
||||
case '"':
|
||||
ss << R"(\")";
|
||||
break;
|
||||
case '\\':
|
||||
ss << R"(\\)";
|
||||
break;
|
||||
case '\033':
|
||||
ss << R"(\e)";
|
||||
break;
|
||||
case '\n':
|
||||
ss << R"(\n)";
|
||||
break;
|
||||
case '\r':
|
||||
ss << R"(\r)";
|
||||
break;
|
||||
case '\t':
|
||||
ss << R"(\t)";
|
||||
break;
|
||||
default: {
|
||||
if ((c >= 32) && (c <= 126)) {
|
||||
ss << static_cast<char>(c);
|
||||
} else {
|
||||
std::uint8_t high{};
|
||||
std::uint8_t low{};
|
||||
int_to_hex(high, low, c);
|
||||
ss << R"(\x)" << static_cast<char>(high) << static_cast<char>(low);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string Ssid::from_hex(const std::string& hex) {
|
||||
std::ostringstream ss;
|
||||
bool high{true};
|
||||
|
||||
error = (hex.size() % 2) != 0;
|
||||
for (const auto& c : hex) {
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
if (high) {
|
||||
tmp = static_cast<std::uint8_t>(c);
|
||||
high = false;
|
||||
} else {
|
||||
const auto output = hex_to_int(tmp, static_cast<std::uint8_t>(c));
|
||||
encode(output, ss);
|
||||
high = true;
|
||||
}
|
||||
}
|
||||
return (error) ? std::string{} : ss.str();
|
||||
}
|
||||
|
||||
std::string WpaCliSetup::hex_to_ssid(const std::string& hex) {
|
||||
Ssid converter;
|
||||
return converter.from_hex(hex);
|
||||
}
|
||||
|
||||
std::string WpaCliSetup::ssid_to_hex(const std::string& ssid) {
|
||||
Ssid converter;
|
||||
return converter.to_hex(ssid);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
122
tools/EVerest-main/modules/Misc/Setup/WiFiSetup.hpp
Normal file
122
tools/EVerest-main/modules/Misc/Setup/WiFiSetup.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef WIFISETUP_HPP
|
||||
#define WIFISETUP_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* SSID encoding
|
||||
* From Wikipedia:
|
||||
* "SSIDs can be zero to 32 octets long, and are, for convenience, usually
|
||||
* in a natural language, such as English"
|
||||
*
|
||||
* wpa-cli escapes SSID strings in scan results; character values 32..126 are
|
||||
* not converted. The following conversions are applied:
|
||||
* - \" double quote
|
||||
* - \\ backslash
|
||||
* - \e escape (\033)
|
||||
* - \n newline
|
||||
* - \r return
|
||||
* - \t tab
|
||||
* - \xnn for other values
|
||||
*
|
||||
* JSON strings are UTF-8 with \ converted to \\
|
||||
*/
|
||||
|
||||
namespace module {
|
||||
|
||||
class Ssid {
|
||||
private:
|
||||
using fn_p = int (Ssid::*)(std::uint8_t c);
|
||||
fn_p handler{nullptr};
|
||||
std::uint8_t tmp{0};
|
||||
bool error{false};
|
||||
|
||||
int standard(std::uint8_t c);
|
||||
int backslash(std::uint8_t c);
|
||||
int hex_1(std::uint8_t c);
|
||||
int hex_2(std::uint8_t c);
|
||||
|
||||
void encode(int c, std::ostringstream& ss);
|
||||
|
||||
public:
|
||||
std::string to_hex(const std::string& ssid);
|
||||
std::string from_hex(const std::string& hex);
|
||||
};
|
||||
|
||||
class WpaCliSetup {
|
||||
public:
|
||||
using flags_t = std::vector<std::string>;
|
||||
|
||||
enum class network_security_t : std::uint8_t {
|
||||
none,
|
||||
wpa2_only,
|
||||
wpa3_only,
|
||||
wpa2_and_wpa3,
|
||||
};
|
||||
|
||||
struct WifiScan {
|
||||
std::string bssid;
|
||||
std::string ssid;
|
||||
flags_t flags;
|
||||
int frequency;
|
||||
int signal_level;
|
||||
};
|
||||
using WifiScanList = std::vector<WifiScan>;
|
||||
|
||||
struct WifiNetworkStatus {
|
||||
std::string interface;
|
||||
std::string ssid;
|
||||
int network_id;
|
||||
int signal_level;
|
||||
bool connected;
|
||||
};
|
||||
using WifiNetworkStatusList = std::vector<WifiNetworkStatus>;
|
||||
|
||||
struct WifiNetwork {
|
||||
std::string ssid;
|
||||
int network_id;
|
||||
};
|
||||
using WifiNetworkList = std::vector<WifiNetwork>;
|
||||
|
||||
using Status = std::map<std::string, std::string>;
|
||||
using Poll = std::map<std::string, std::string>;
|
||||
|
||||
protected:
|
||||
virtual bool do_scan(const std::string& interface);
|
||||
virtual WifiScanList do_scan_results(const std::string& interface);
|
||||
virtual Status do_status(const std::string& interface);
|
||||
virtual Poll do_signal_poll(const std::string& interface);
|
||||
virtual flags_t parse_flags(const std::string& flags);
|
||||
|
||||
public:
|
||||
virtual ~WpaCliSetup() = default;
|
||||
virtual int add_network(const std::string& interface);
|
||||
virtual bool set_network(const std::string& interface, int network_id, const std::string& ssid,
|
||||
const std::string& psk, network_security_t mode, bool hidden);
|
||||
virtual bool set_network(const std::string& interface, int network_id, const std::string& ssid,
|
||||
const std::string& psk, bool hidden) {
|
||||
return set_network(interface, network_id, ssid, psk, network_security_t::wpa2_and_wpa3, hidden);
|
||||
}
|
||||
virtual bool enable_network(const std::string& interface, int network_id);
|
||||
virtual bool disable_network(const std::string& interface, int network_id);
|
||||
virtual bool select_network(const std::string& interface, int network_id);
|
||||
virtual bool remove_network(const std::string& interface, int network_id);
|
||||
virtual bool save_config(const std::string& interface);
|
||||
virtual WifiScanList scan_wifi(const std::string& interface);
|
||||
virtual WifiNetworkList list_networks(const std::string& interface);
|
||||
virtual WifiNetworkStatusList list_networks_status(const std::string& interface);
|
||||
virtual bool is_wifi_interface(const std::string& interface);
|
||||
|
||||
static std::string hex_to_ssid(const std::string& hex);
|
||||
static std::string ssid_to_hex(const std::string& ssid);
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // WIFISETUP_HPP
|
||||
44
tools/EVerest-main/modules/Misc/Setup/manifest.yaml
Normal file
44
tools/EVerest-main/modules/Misc/Setup/manifest.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
description: >-
|
||||
The EVerest Setup module for setting up a LAN or WIFI network connection. This module needs privileged access and
|
||||
should not run during normal operations
|
||||
config:
|
||||
setup_wifi:
|
||||
description: Allow wifi setup
|
||||
type: boolean
|
||||
default: false
|
||||
localization:
|
||||
description: Enable localization support
|
||||
type: boolean
|
||||
default: false
|
||||
setup_simulation:
|
||||
description: Allow simulation setup
|
||||
type: boolean
|
||||
default: false
|
||||
online_check_host:
|
||||
description: Hostname or IP to use to check for internet connectivity
|
||||
type: string
|
||||
default: lfenergy.org
|
||||
initialized_by_default:
|
||||
description: Always report as if the charger was initialized
|
||||
type: boolean
|
||||
default: true
|
||||
release_metadata_file:
|
||||
description: Location of the release metadata file relative to the EVerest prefix
|
||||
type: string
|
||||
default: "release.json"
|
||||
ap_interface:
|
||||
description: Wifi interface for AP mode
|
||||
type: string
|
||||
default: wlan0
|
||||
ap_ipv4:
|
||||
description: IPv4 address of the AP
|
||||
type: string
|
||||
default: "192.168.1.1/24"
|
||||
requires:
|
||||
store:
|
||||
interface: kvs
|
||||
enable_external_mqtt: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Kai-Uwe Hermann
|
||||
19
tools/EVerest-main/modules/Misc/Setup/tests/CMakeLists.txt
Normal file
19
tools/EVerest-main/modules/Misc/Setup/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
set(TEST_TARGET_NAME ${PROJECT_NAME}_setup_tests)
|
||||
add_executable(${TEST_TARGET_NAME})
|
||||
|
||||
target_include_directories(${TEST_TARGET_NAME} PUBLIC ${GTEST_INCLUDE_DIRS} . ..)
|
||||
|
||||
target_sources(${TEST_TARGET_NAME} PRIVATE
|
||||
RunApplicationStub.cpp
|
||||
WiFiSetupTest.cpp
|
||||
../WiFiSetup.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${TEST_TARGET_NAME} PRIVATE
|
||||
GTest::gtest_main
|
||||
nlohmann_json::nlohmann_json
|
||||
everest::run_application
|
||||
)
|
||||
|
||||
add_test(${TEST_TARGET_NAME} ${TEST_TARGET_NAME})
|
||||
ev_register_test_target(${TEST_TARGET_NAME})
|
||||
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "RunApplicationStub.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace everest::run_application;
|
||||
|
||||
namespace stub {
|
||||
|
||||
RunApplication* RunApplication::active_p = nullptr;
|
||||
|
||||
RunApplication::RunApplication() :
|
||||
results({
|
||||
{"add_network", {{}, {{"0"}}, 0}},
|
||||
{"set_network", {{}, {{"OK"}}, 0}},
|
||||
{"enable_network", {{}, {{"OK"}}, 0}},
|
||||
{"disable_network", {{}, {{"OK"}}, 0}},
|
||||
{"select_network", {{}, {{"OK"}}, 0}},
|
||||
{"remove_network", {{}, {{"OK"}}, 0}},
|
||||
{"save_config", {{}, {{"OK"}}, 0}},
|
||||
// scan_wifi uses scan and scan_results
|
||||
{"scan", {{}, {{"OK"}}, 0}},
|
||||
{"scan_results",
|
||||
{{},
|
||||
{
|
||||
{"bssid / frequency / signal level / flags / ssid"},
|
||||
},
|
||||
0}},
|
||||
{"list_networks",
|
||||
{{},
|
||||
{
|
||||
{"network id / ssid / bssid / flags"},
|
||||
},
|
||||
0}},
|
||||
// list_networks_status uses list_networks status signal_poll
|
||||
{"status",
|
||||
{{},
|
||||
{
|
||||
{"wpa_state=INACTIVE"},
|
||||
{"p2p_device_address=c2:ee:40:b0:57:b8"},
|
||||
{"address=c0:ee:40:b0:57:b8"},
|
||||
{"uuid=7dd9abf8-53f0-532b-a763-2f43537e4234"},
|
||||
},
|
||||
0}},
|
||||
{"signal_poll", {{}, {{"FAIL"}}, 0}},
|
||||
}),
|
||||
signal_poll_called(false),
|
||||
psk_called(false),
|
||||
sae_password_called(false),
|
||||
key_mgmt_called(false),
|
||||
scan_ssid_called(false),
|
||||
ieee80211w_called(false),
|
||||
key_mgmt_value(),
|
||||
ieee80211w_value() {
|
||||
active_p = this;
|
||||
}
|
||||
|
||||
RunApplication::~RunApplication() {
|
||||
active_p = nullptr;
|
||||
}
|
||||
|
||||
CmdOutput RunApplication::run_application(const std::string& name, std::vector<std::string> args) {
|
||||
CmdOutput result = {{}, {}, -1};
|
||||
EXPECT_EQ(name, "/usr/sbin/wpa_cli");
|
||||
EXPECT_EQ(args[0], "-i");
|
||||
if (args[2] == "signal_poll") {
|
||||
signal_poll_called = true;
|
||||
} else if (args[2] == "set_network") {
|
||||
if (args[4] == "psk") {
|
||||
psk_called = true;
|
||||
} else if (args[4] == "sae_password") {
|
||||
sae_password_called = true;
|
||||
} else if (args[4] == "key_mgmt") {
|
||||
key_mgmt_called = true;
|
||||
key_mgmt_value = args[5];
|
||||
} else if (args[4] == "ieee80211w") {
|
||||
ieee80211w_called = true;
|
||||
ieee80211w_value = args[5];
|
||||
} else if (args[4] == "scan_ssid") {
|
||||
scan_ssid_called = true;
|
||||
}
|
||||
}
|
||||
auto it = results.find(args[2]);
|
||||
if (it != results.end()) {
|
||||
result = it->second;
|
||||
if (!result.split_output.empty() && result.output.empty()) {
|
||||
for (auto& line : result.output) {
|
||||
result.output += line + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace stub
|
||||
|
||||
namespace everest::run_application {
|
||||
CmdOutput run_application(const std::string& name, std::vector<std::string> args,
|
||||
const std::function<CmdControl(const std::string& output_line)> output_callback) {
|
||||
CmdOutput result = {{}, {}, -1};
|
||||
if (stub::RunApplication::active_p != nullptr) {
|
||||
result = std::move(stub::RunApplication::active_p->run_application(name, args));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace everest::run_application
|
||||
@@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef RUNAPPLICATIONSTUB_HPP
|
||||
#define RUNAPPLICATIONSTUB_HPP
|
||||
|
||||
#include <everest/run_application/run_application.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace stub {
|
||||
|
||||
class RunApplication {
|
||||
public:
|
||||
static RunApplication* active_p;
|
||||
|
||||
std::map<std::string, everest::run_application::CmdOutput> results;
|
||||
bool signal_poll_called;
|
||||
bool psk_called;
|
||||
bool sae_password_called;
|
||||
bool key_mgmt_called;
|
||||
bool scan_ssid_called;
|
||||
bool ieee80211w_called;
|
||||
std::string key_mgmt_value;
|
||||
std::string ieee80211w_value;
|
||||
|
||||
RunApplication();
|
||||
virtual ~RunApplication();
|
||||
|
||||
virtual everest::run_application::CmdOutput run_application(const std::string& name, std::vector<std::string> args);
|
||||
};
|
||||
|
||||
} // namespace stub
|
||||
namespace everest::run_application {
|
||||
CmdOutput run_application(const std::string& name, std::vector<std::string> args,
|
||||
const std::function<CmdControl(const std::string& output_line)> output_callback);
|
||||
}
|
||||
|
||||
#endif // RUNAPPLICATIONSTUB_HPP
|
||||
726
tools/EVerest-main/modules/Misc/Setup/tests/WiFiSetupTest.cpp
Normal file
726
tools/EVerest-main/modules/Misc/Setup/tests/WiFiSetupTest.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "RunApplicationStub.hpp"
|
||||
#include <WiFiSetup.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
using namespace module;
|
||||
using nlohmann::json;
|
||||
|
||||
constexpr const char* example_psk = "e3003974af901976485f3e655b455791dcc20a5380f42a7839de3bfdc9d70d71";
|
||||
constexpr const char* example_password = "LetMeIn2";
|
||||
constexpr const char* example_long_password = "e3003974af901976485f3e655b455791dcc20a5380f42a7839de3bfdc9d70d71X";
|
||||
|
||||
class WpaCliSetupTest : public WpaCliSetup {
|
||||
public:
|
||||
// override to support testing
|
||||
virtual bool is_wifi_interface(const std::string& interface) override {
|
||||
if (interface == "ap0") {
|
||||
return false;
|
||||
} else if (interface == "eth0") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
struct WifiCredentials {
|
||||
std::string interface;
|
||||
std::string ssid;
|
||||
std::string psk;
|
||||
bool hidden;
|
||||
|
||||
operator std::string() {
|
||||
|
||||
json wifi_credentials = *this;
|
||||
|
||||
return wifi_credentials.dump();
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const WifiCredentials& k) {
|
||||
j = json::object({{"interface", k.interface}, {"ssid", k.ssid}, {"psk", k.psk}, {"hidden", k.hidden}});
|
||||
}
|
||||
|
||||
void from_json(const json& j, WifiCredentials& k) {
|
||||
k.interface = j.at("interface");
|
||||
k.ssid = j.at("ssid");
|
||||
k.psk = j.at("psk");
|
||||
k.hidden = false;
|
||||
// optional item
|
||||
auto it = j.find("hidden");
|
||||
if ((it != j.end() && *it)) {
|
||||
k.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SSID conversions
|
||||
TEST(Ssid, toHex) {
|
||||
Ssid ssid;
|
||||
EXPECT_EQ(ssid.to_hex("0123456789"), "30313233343536373839");
|
||||
EXPECT_EQ(ssid.to_hex("abcdef"), "616263646566");
|
||||
EXPECT_EQ(ssid.to_hex("ABCDEF"), "414243444546");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\" \\ \e\n\r\t)"), "22205c201b0a0d09");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\x00\x01\xfd)"), "0001fd");
|
||||
}
|
||||
|
||||
TEST(Ssid, fromHex) {
|
||||
Ssid ssid;
|
||||
EXPECT_EQ(ssid.from_hex("30313233343536373839"), "0123456789");
|
||||
EXPECT_EQ(ssid.from_hex("616263646566"), "abcdef");
|
||||
EXPECT_EQ(ssid.from_hex("414243444546"), "ABCDEF");
|
||||
EXPECT_EQ(ssid.from_hex("22205c201b0a0d09"), R"(\" \\ \e\n\r\t)");
|
||||
EXPECT_EQ(ssid.from_hex("0001fd"), R"(\x00\x01\xfd)");
|
||||
}
|
||||
|
||||
TEST(Ssid, complete) {
|
||||
Ssid ssid;
|
||||
|
||||
std::stringstream ss;
|
||||
for (std::uint16_t i = 0; i < 256; i++) {
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << i;
|
||||
}
|
||||
const std::string values_str(ss.str());
|
||||
const auto result_str = ssid.from_hex(values_str);
|
||||
const auto result_hex = ssid.to_hex(result_str);
|
||||
// std::cout << result_str << std::endl;
|
||||
// std::cout << result_hex << std::endl;
|
||||
EXPECT_EQ(values_str, result_hex);
|
||||
}
|
||||
|
||||
TEST(Ssid, unusual) {
|
||||
Ssid ssid;
|
||||
|
||||
// allowing upper case hex digits
|
||||
EXPECT_EQ(ssid.from_hex("E0E1E2E3E4E5E6E7E8E9EaEbEcEdEeEfEAEBECEDEEEF"),
|
||||
R"(\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xea\xeb\xec\xed\xee\xef)");
|
||||
EXPECT_EQ(
|
||||
ssid.to_hex(R"(\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xEA\xEB\xEC\xED\xEE\xEF)"),
|
||||
"e0e1e2e3e4e5e6e7e8e9eaebecedeeefeaebecedeeef");
|
||||
|
||||
// parsing errors
|
||||
EXPECT_EQ(ssid.to_hex(R"(123\?456)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(123\?)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\?456)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\034)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\03)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\0)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\x)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\xz)"), "");
|
||||
EXPECT_EQ(ssid.to_hex(R"(\xaz)"), "");
|
||||
|
||||
EXPECT_EQ(ssid.from_hex(R"(G123)"), "");
|
||||
EXPECT_EQ(ssid.from_hex(R"(12G3)"), "");
|
||||
EXPECT_EQ(ssid.from_hex(R"(123G)"), "");
|
||||
EXPECT_EQ(ssid.from_hex(R"(1234568)"), "");
|
||||
}
|
||||
|
||||
TEST(Ssid, json) {
|
||||
/*
|
||||
* worked example
|
||||
* ssid=PP€-310034
|
||||
* scan_results
|
||||
* bssid / frequency / signal level / flags / ssid
|
||||
* c2:ee:40:10:57:b8 2417 -45 [WPA2-PSK-CCMP][ESS] PP\xe2\x82\xac-310034
|
||||
*
|
||||
* MQTT
|
||||
* everest_api/setup/var/wifi_info: [
|
||||
* {"bssid":"c2:ee:40:10:57:b8","flags":["WPA2-PSK-CCMP","ESS"],"frequency":2417,"signal_level":-46,"ssid":"PP\\xe2\\x82\\xac-310034"}]
|
||||
*/
|
||||
Ssid conv;
|
||||
|
||||
std::string ssid_hex{"535349443de282ac3132"};
|
||||
std::string ssid = conv.from_hex(ssid_hex);
|
||||
WifiCredentials wifi = {"eth0", ssid, "\"psk\"", false};
|
||||
nlohmann::json j;
|
||||
to_json(j, wifi);
|
||||
|
||||
const auto transmitted = j.dump();
|
||||
WifiCredentials received = json::parse(transmitted);
|
||||
EXPECT_EQ(received.ssid, ssid);
|
||||
|
||||
const auto rec_ssid_hex = conv.to_hex(received.ssid);
|
||||
EXPECT_EQ(rec_ssid_hex, ssid_hex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// add_network()
|
||||
TEST(add_network, wired) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_EQ(obj.add_network("eth0"), -1);
|
||||
}
|
||||
|
||||
TEST(add_network, wireless) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_NE(obj.add_network("wlan0"), -1);
|
||||
}
|
||||
|
||||
TEST(add_network, access_point) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_EQ(obj.add_network("ap0"), -1);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// set_network()
|
||||
TEST(set_network, none_no_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", "", WpaCliSetup::network_security_t::none, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, none_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(
|
||||
obj.set_network("wlan0", 0, "PlusnetWireless", example_psk, WpaCliSetup::network_security_t::none, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, none_password) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(
|
||||
obj.set_network("wlan0", 0, "PlusnetWireless", example_password, WpaCliSetup::network_security_t::none, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_no_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", "", WpaCliSetup::network_security_t::wpa2_only, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(
|
||||
obj.set_network("wlan0", 0, "PlusnetWireless", example_psk, WpaCliSetup::network_security_t::wpa2_only, false));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "WPA-PSK");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_password) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", example_password,
|
||||
WpaCliSetup::network_security_t::wpa2_only, false));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "WPA-PSK");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa3_no_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", "", WpaCliSetup::network_security_t::wpa3_only, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa3_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(
|
||||
obj.set_network("wlan0", 0, "PlusnetWireless", example_psk, WpaCliSetup::network_security_t::wpa3_only, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.sae_password_called);
|
||||
ASSERT_TRUE(ra.ieee80211w_called);
|
||||
ASSERT_EQ(ra.ieee80211w_value, "2");
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "SAE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa3_password) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", example_password,
|
||||
WpaCliSetup::network_security_t::wpa3_only, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.sae_password_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_TRUE(ra.ieee80211w_called);
|
||||
ASSERT_EQ(ra.ieee80211w_value, "2");
|
||||
ASSERT_EQ(ra.key_mgmt_value, "SAE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_and_wpa3_no_psk) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(
|
||||
obj.set_network("wlan0", 0, "PlusnetWireless", "", WpaCliSetup::network_security_t::wpa2_and_wpa3, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "NONE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_and_wpa3_psk) {
|
||||
// with a PSK result is same as wpa2_only
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", example_psk,
|
||||
WpaCliSetup::network_security_t::wpa2_and_wpa3, false));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_FALSE(ra.ieee80211w_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "WPA-PSK");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_and_wpa3_password) {
|
||||
// configure for both
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", example_password,
|
||||
WpaCliSetup::network_security_t::wpa2_and_wpa3, false));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_FALSE(ra.sae_password_called);
|
||||
ASSERT_TRUE(ra.ieee80211w_called);
|
||||
ASSERT_EQ(ra.ieee80211w_value, "1");
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "WPA-PSK WPA-PSK-SHA256 SAE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2_and_wpa3_password_long) {
|
||||
// configure for WPA3 only
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", example_long_password,
|
||||
WpaCliSetup::network_security_t::wpa2_and_wpa3, false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.sae_password_called);
|
||||
ASSERT_TRUE(ra.ieee80211w_called);
|
||||
ASSERT_EQ(ra.ieee80211w_value, "2");
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_EQ(ra.key_mgmt_value, "SAE");
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, wpa2) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "PlusnetWireless", "LetMeIn2", false));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, open) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "OpenNet", "", false));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_FALSE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, hidden_wpa2) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "Hidden", "LetMeIn3", true));
|
||||
ASSERT_TRUE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_TRUE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
TEST(set_network, hidden_open) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.set_network("wlan0", 0, "Hidden", "", true));
|
||||
ASSERT_FALSE(ra.psk_called);
|
||||
ASSERT_TRUE(ra.key_mgmt_called);
|
||||
ASSERT_TRUE(ra.scan_ssid_called);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// enable_network()
|
||||
TEST(enable_network, exists) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.enable_network("wlan0", 0));
|
||||
}
|
||||
|
||||
TEST(enable_network, doesnt_exist) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["enable_network"] = {{}, {{"FAIL"}}, 0};
|
||||
WpaCliSetupTest obj;
|
||||
// still returns an exit code of 0
|
||||
ASSERT_TRUE(obj.enable_network("wlan0", 1));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// disable_network()
|
||||
TEST(disable_network, exists) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.disable_network("wlan0", 0));
|
||||
}
|
||||
|
||||
TEST(disable_network, doesnt_exist) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["disable_network"] = {{}, {{"FAIL"}}, 0};
|
||||
WpaCliSetupTest obj;
|
||||
// still returns an exit code of 0
|
||||
ASSERT_TRUE(obj.disable_network("wlan0", 1));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// select_network()
|
||||
TEST(select_network, exists) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.select_network("wlan0", 0));
|
||||
}
|
||||
|
||||
TEST(select_network, doesnt_exist) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["select_network"] = {{}, {{"FAIL"}}, 0};
|
||||
WpaCliSetupTest obj;
|
||||
// still returns an exit code of 0
|
||||
ASSERT_TRUE(obj.select_network("wlan0", 1));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// remove_network()
|
||||
TEST(remove_network, exists) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.remove_network("wlan0", 0));
|
||||
}
|
||||
|
||||
TEST(remove_network, doesnt_exist) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["remove_network"] = {{}, {{"FAIL"}}, 0};
|
||||
WpaCliSetupTest obj;
|
||||
// still returns an exit code of 0
|
||||
ASSERT_TRUE(obj.remove_network("wlan0", 1));
|
||||
}
|
||||
|
||||
TEST(remove_network, fail) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["remove_network"] = {{}, {{"Invalid REMOVE_NETWORK command - at least 1 argument is required."}}, 255};
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_FALSE(obj.remove_network("wlan0", -99));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// save_config()
|
||||
TEST(save_config, success) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_TRUE(obj.save_config("wlan0"));
|
||||
}
|
||||
|
||||
TEST(save_config, fail) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
ASSERT_FALSE(obj.save_config("ap0"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// scan_wifi()
|
||||
TEST(scan_wifi, none) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.scan_wifi("wlan0");
|
||||
ASSERT_TRUE(res.empty());
|
||||
}
|
||||
|
||||
TEST(scan_wifi, some) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["scan_results"] = {
|
||||
{},
|
||||
{
|
||||
{"bssid / frequency / signal level / flags / ssid"},
|
||||
{"14:49:bc:06:81:19\t2412\t-72\t[WPA2-PSK-CCMP][ESS]\tPlusnetWireless"},
|
||||
{"6a:82:8c:38:b2:a1\t2412\t-93\t[WPA2-PSK-CCMP][ESS]\t\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"},
|
||||
},
|
||||
0};
|
||||
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.scan_wifi("wlan0");
|
||||
ASSERT_FALSE(res.empty());
|
||||
ASSERT_EQ(res.size(), 2);
|
||||
|
||||
module::WpaCliSetup::flags_t expected = {"WPA2-PSK-CCMP", "ESS"};
|
||||
|
||||
EXPECT_EQ(res[0].bssid, "14:49:bc:06:81:19");
|
||||
EXPECT_EQ(res[0].ssid, "PlusnetWireless");
|
||||
EXPECT_EQ(res[0].frequency, 2412);
|
||||
EXPECT_EQ(res[0].signal_level, -72);
|
||||
EXPECT_EQ(res[0].flags, expected);
|
||||
|
||||
EXPECT_EQ(res[1].bssid, "6a:82:8c:38:b2:a1");
|
||||
EXPECT_EQ(res[1].ssid, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00");
|
||||
EXPECT_EQ(res[1].frequency, 2412);
|
||||
EXPECT_EQ(res[1].signal_level, -93);
|
||||
EXPECT_EQ(res[1].flags, expected);
|
||||
}
|
||||
|
||||
TEST(scan_wifi, more) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["scan_results"] = {
|
||||
{},
|
||||
{
|
||||
{"bssid / frequency / signal level / flags / ssid"},
|
||||
{"14:49:bc:06:81:19\t2412\t-71\t[WPA2-PSK-CCMP][ESS]\tPlusnetWireless"},
|
||||
{"14:49:bc:06:81:1b\t2412\t-71\t[WPA2-PSK-CCMP][ESS]\t\\x00\\x00\\x00\\x00\\x00\\x00\\x00"},
|
||||
{"00:1e:42:33:62:07\t2462\t-89\t[WPA2-PSK-CCMP+TKIP][ESS][UTF-8]\tRUT950_6207"},
|
||||
{"b4:ba:9d:16:e2:ba\t2437\t-92\t[WPA2-PSK-CCMP][WPS][ESS]\tSKYLZMEY"},
|
||||
{"14:49:bc:06:81:1c\t2412\t-72\t[ESS]\tTesting123"},
|
||||
{"36:49:5b:f8:e1:07\t2412\t-92\t[ESS]\tEE WiFi"},
|
||||
{"14:49:bc:06:81:18\t2412\t-73\t[WPA2-PSK-CCMP][ESS]\t\\x00\\x00\\x00\\x00\\x00\\x00\\x00"},
|
||||
{"6a:82:8c:38:b2:a1\t2412\t-88\t[WPA2-PSK-CCMP][ESS]\t\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"},
|
||||
{"18:82:8c:38:b2:a5\t2412\t-92\t[WPA2-PSK-CCMP][WPS][ESS]\tBT-3GAG3M"},
|
||||
{"6a:82:8c:38:b2:a6\t2412\t-92\t[ESS]\tEE WiFi"},
|
||||
},
|
||||
0};
|
||||
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.scan_wifi("wlan0");
|
||||
ASSERT_FALSE(res.empty());
|
||||
ASSERT_EQ(res.size(), 10);
|
||||
|
||||
module::WpaCliSetup::flags_t expected1 = {"WPA2-PSK-CCMP", "ESS"};
|
||||
module::WpaCliSetup::flags_t expected2 = {"WPA2-PSK-CCMP+TKIP", "ESS", "UTF-8"};
|
||||
module::WpaCliSetup::flags_t expected3 = {"WPA2-PSK-CCMP", "WPS", "ESS"};
|
||||
module::WpaCliSetup::flags_t expected4 = {"ESS"};
|
||||
|
||||
EXPECT_EQ(res[0].bssid, "14:49:bc:06:81:19");
|
||||
EXPECT_EQ(res[0].ssid, "PlusnetWireless");
|
||||
EXPECT_EQ(res[0].frequency, 2412);
|
||||
EXPECT_EQ(res[0].signal_level, -71);
|
||||
EXPECT_EQ(res[0].flags, expected1);
|
||||
|
||||
EXPECT_EQ(res[1].bssid, "14:49:bc:06:81:1b");
|
||||
EXPECT_EQ(res[1].ssid, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00");
|
||||
EXPECT_EQ(res[1].frequency, 2412);
|
||||
EXPECT_EQ(res[1].signal_level, -71);
|
||||
EXPECT_EQ(res[1].flags, expected1);
|
||||
|
||||
EXPECT_EQ(res[2].bssid, "00:1e:42:33:62:07");
|
||||
EXPECT_EQ(res[2].ssid, "RUT950_6207");
|
||||
EXPECT_EQ(res[2].frequency, 2462);
|
||||
EXPECT_EQ(res[2].signal_level, -89);
|
||||
EXPECT_EQ(res[2].flags, expected2);
|
||||
|
||||
EXPECT_EQ(res[3].bssid, "b4:ba:9d:16:e2:ba");
|
||||
EXPECT_EQ(res[3].ssid, "SKYLZMEY");
|
||||
EXPECT_EQ(res[3].frequency, 2437);
|
||||
EXPECT_EQ(res[3].signal_level, -92);
|
||||
EXPECT_EQ(res[3].flags, expected3);
|
||||
|
||||
EXPECT_EQ(res[4].bssid, "14:49:bc:06:81:1c");
|
||||
EXPECT_EQ(res[4].ssid, "Testing123");
|
||||
EXPECT_EQ(res[4].frequency, 2412);
|
||||
EXPECT_EQ(res[4].signal_level, -72);
|
||||
EXPECT_EQ(res[4].flags, expected4);
|
||||
|
||||
EXPECT_EQ(res[5].bssid, "36:49:5b:f8:e1:07");
|
||||
EXPECT_EQ(res[5].ssid, "EE WiFi");
|
||||
EXPECT_EQ(res[5].frequency, 2412);
|
||||
EXPECT_EQ(res[5].signal_level, -92);
|
||||
EXPECT_EQ(res[5].flags, expected4);
|
||||
|
||||
EXPECT_EQ(res[6].bssid, "14:49:bc:06:81:18");
|
||||
EXPECT_EQ(res[6].ssid, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00");
|
||||
EXPECT_EQ(res[6].frequency, 2412);
|
||||
EXPECT_EQ(res[6].signal_level, -73);
|
||||
EXPECT_EQ(res[6].flags, expected1);
|
||||
|
||||
EXPECT_EQ(res[7].bssid, "6a:82:8c:38:b2:a1");
|
||||
EXPECT_EQ(res[7].ssid, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00");
|
||||
EXPECT_EQ(res[7].frequency, 2412);
|
||||
EXPECT_EQ(res[7].signal_level, -88);
|
||||
EXPECT_EQ(res[7].flags, expected1);
|
||||
|
||||
EXPECT_EQ(res[8].bssid, "18:82:8c:38:b2:a5");
|
||||
EXPECT_EQ(res[8].ssid, "BT-3GAG3M");
|
||||
EXPECT_EQ(res[8].frequency, 2412);
|
||||
EXPECT_EQ(res[8].signal_level, -92);
|
||||
EXPECT_EQ(res[8].flags, expected3);
|
||||
|
||||
EXPECT_EQ(res[9].bssid, "6a:82:8c:38:b2:a6");
|
||||
EXPECT_EQ(res[9].ssid, "EE WiFi");
|
||||
EXPECT_EQ(res[9].frequency, 2412);
|
||||
EXPECT_EQ(res[9].signal_level, -92);
|
||||
EXPECT_EQ(res[9].flags, expected4);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// list_networks()
|
||||
TEST(list_networks, none) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.list_networks("wlan0");
|
||||
ASSERT_TRUE(res.empty());
|
||||
}
|
||||
|
||||
TEST(list_networks, one) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["list_networks"] = {{},
|
||||
{
|
||||
{"network id / ssid / bssid / flags"},
|
||||
{"0\t\tany\t[DISABLED]"},
|
||||
},
|
||||
0};
|
||||
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.list_networks("wlan0");
|
||||
ASSERT_FALSE(res.empty());
|
||||
ASSERT_EQ(res.size(), 1);
|
||||
|
||||
module::WpaCliSetup::flags_t expected = {"WPA2-PSK-CCMP", "ESS"};
|
||||
|
||||
EXPECT_EQ(res[0].network_id, 0);
|
||||
EXPECT_EQ(res[0].ssid, "");
|
||||
}
|
||||
|
||||
TEST(list_networks, two) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["list_networks"] = {{},
|
||||
{
|
||||
{"network id / ssid / bssid / flags"},
|
||||
{"0\t\tany\t[DISABLED]"},
|
||||
{"1\tPlusnetWireless\tany\t[CURRENT]"},
|
||||
},
|
||||
0};
|
||||
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.list_networks("wlan0");
|
||||
ASSERT_FALSE(res.empty());
|
||||
ASSERT_EQ(res.size(), 2);
|
||||
|
||||
module::WpaCliSetup::flags_t expected = {"WPA2-PSK-CCMP", "ESS"};
|
||||
|
||||
EXPECT_EQ(res[0].network_id, 0);
|
||||
EXPECT_EQ(res[0].ssid, "");
|
||||
|
||||
EXPECT_EQ(res[1].network_id, 1);
|
||||
EXPECT_EQ(res[1].ssid, "PlusnetWireless");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// list_networks_status()
|
||||
TEST(list_networks, not_connected) {
|
||||
stub::RunApplication ra;
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.list_networks_status("wlan0");
|
||||
ASSERT_TRUE(res.empty());
|
||||
ASSERT_FALSE(ra.signal_poll_called);
|
||||
}
|
||||
|
||||
TEST(list_networks, connected) {
|
||||
stub::RunApplication ra;
|
||||
ra.results["list_networks"] = {{},
|
||||
{
|
||||
{"network id / ssid / bssid / flags"},
|
||||
{"0\t\tany\t[DISABLED]"},
|
||||
{"1\tPlusnetWireless\tany\t[CURRENT]"},
|
||||
{"2\tHiddenNet\tany\t[DISABLED]"},
|
||||
},
|
||||
0};
|
||||
ra.results["status"] = {{},
|
||||
{
|
||||
{"bssid=14:49:bc:06:81:19"},
|
||||
{"freq=2412"},
|
||||
{"ssid=PlusnetWireless"},
|
||||
{"id=1"},
|
||||
{"mode=station"},
|
||||
{"wifi_generation=4"},
|
||||
{"pairwise_cipher=CCMP"},
|
||||
{"group_cipher=CCMP"},
|
||||
{"key_mgmt=WPA2-PSK"},
|
||||
{"wpa_state=COMPLETED"},
|
||||
{"ip_address=172.25.1.11"},
|
||||
{"p2p_device_address=c2:ee:40:b0:57:b8"},
|
||||
{"address=c0:ee:40:b0:57:b8"},
|
||||
{"uuid=7dd9abf8-53f0-532b-a763-2f43537e4234"},
|
||||
},
|
||||
0};
|
||||
ra.results["signal_poll"] = {{},
|
||||
{
|
||||
{"RSSI=-73"},
|
||||
{"LINKSPEED=54"},
|
||||
{"NOISE=9999"},
|
||||
{"FREQUENCY=2412"},
|
||||
{"WIDTH=20 MHz"},
|
||||
{"CENTER_FRQ1=2412"},
|
||||
},
|
||||
0};
|
||||
WpaCliSetupTest obj;
|
||||
auto res = obj.list_networks_status("wlan0");
|
||||
ASSERT_FALSE(res.empty());
|
||||
ASSERT_TRUE(ra.signal_poll_called);
|
||||
ASSERT_EQ(res.size(), 3);
|
||||
|
||||
EXPECT_EQ(res[0].interface, "wlan0");
|
||||
EXPECT_EQ(res[0].network_id, 0);
|
||||
EXPECT_EQ(res[0].ssid, "");
|
||||
EXPECT_FALSE(res[0].connected);
|
||||
EXPECT_EQ(res[0].signal_level, -100);
|
||||
|
||||
EXPECT_EQ(res[1].interface, "wlan0");
|
||||
EXPECT_EQ(res[1].network_id, 1);
|
||||
EXPECT_EQ(res[1].ssid, "PlusnetWireless");
|
||||
EXPECT_TRUE(res[1].connected);
|
||||
EXPECT_EQ(res[1].signal_level, -73);
|
||||
|
||||
EXPECT_EQ(res[2].interface, "wlan0");
|
||||
EXPECT_EQ(res[2].network_id, 2);
|
||||
EXPECT_EQ(res[2].ssid, "HiddenNet");
|
||||
EXPECT_FALSE(res[2].connected);
|
||||
EXPECT_EQ(res[2].signal_level, -100);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// is_wifi_interface()
|
||||
// not tested as it is checking for files in /proc so depends on the
|
||||
// machine the tests are running on
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user