mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Add additional WiFi code.
This commit is contained in:
@@ -7,9 +7,11 @@
|
||||
#include <sdbus-c++/Error.h>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/Types.h>
|
||||
#include <systemd/sd-id128.h>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/linux/dbus.h"
|
||||
#include "internal/platform/implementation/linux/networkmanager_connection_active_client_glue.h"
|
||||
#include "internal/platform/implementation/linux/networkmanager_device_wireless_client_glue.h"
|
||||
#include "internal/platform/implementation/linux/wifi_medium.h"
|
||||
#include "internal/platform/implementation/wifi.h"
|
||||
@@ -17,21 +19,60 @@
|
||||
namespace nearby {
|
||||
namespace linux {
|
||||
|
||||
std::ostream &operator<<(std::ostream &s,
|
||||
const ActiveConnectionStateReason &reason) {
|
||||
switch (reason) {
|
||||
case kStateReasonUnknown:
|
||||
return s << "The reason for the active connection state change is unknown.";
|
||||
case kStateReasonNone:
|
||||
return s << "No reason was given for the active connection state change.";
|
||||
case kStateReasonUserDisconnected:
|
||||
return s << "The active connection changed state because the user "
|
||||
"disconnected it.";
|
||||
case kStateReasonDeviceDisconnected:
|
||||
return s << "The active connection changed state because the device it was "
|
||||
"using was disconnected.";
|
||||
case kStateReasonServiceStopped:
|
||||
return s << "The service providing the VPN connection was stopped.";
|
||||
case kStateReasonIPConfigInvalid:
|
||||
return s << "The IP config of the active connection was invalid.";
|
||||
case kStateReasonConnectTimeout:
|
||||
return s << "The connection attempt to the VPN service timed out.";
|
||||
case kStateReasonServiceStartTimeout:
|
||||
return s << "A timeout occurred while starting the service providing the "
|
||||
"VPN connection.";
|
||||
case kStateReasonServiceStartFailed:
|
||||
return s << "Starting the service providing the VPN connection failed.";
|
||||
case kStateReasonNoSecrets:
|
||||
return s << "Necessary secrets for the connection were not provided.";
|
||||
case kStateReasonLoginFailed:
|
||||
return s << "Authentication to the server failed.";
|
||||
case kStateReasonConnectionRemoved:
|
||||
return s << "The connection was deleted from settings.";
|
||||
case kStateReasonDependencyFailed:
|
||||
return s << "Master connection of this connection failed to activate.";
|
||||
case kStateReasonDeviceRealizeFailed:
|
||||
return s << "Could not create the software device link.";
|
||||
case kStateReasonDeviceRemoved:
|
||||
return s << "The device this connection depended on disappeared.";
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<NetworkManagerIP4Config>
|
||||
NetworkManagerObjectManager::GetIp4Config(
|
||||
const sdbus::ObjectPath &access_point) {
|
||||
const sdbus::ObjectPath &active_connection) {
|
||||
auto objects = GetManagedObjects();
|
||||
for (auto &[object_path, interfaces] : objects) {
|
||||
if (object_path.find("/org/freedesktop/NetworkManager/ActiveConnection/",
|
||||
0) == 0) {
|
||||
if (interfaces.count(
|
||||
"org.freedesktop.NetworkManager.Connection.Active") == 1) {
|
||||
auto props =
|
||||
interfaces["org.freedesktop.NetworkManager.Connection.Active"];
|
||||
if (interfaces.count(org::freedesktop::NetworkManager::Connection::
|
||||
Active_proxy::INTERFACE_NAME) == 1) {
|
||||
auto props = interfaces[org::freedesktop::NetworkManager::Connection::
|
||||
Active_proxy::INTERFACE_NAME];
|
||||
sdbus::ObjectPath specific_object = props["SpecificObject"];
|
||||
sdbus::ObjectPath ip4config = props["Ip4Config"];
|
||||
|
||||
if (specific_object == access_point)
|
||||
if (specific_object == active_connection)
|
||||
return std::make_unique<NetworkManagerIP4Config>(
|
||||
getProxy().getConnection(), ip4config);
|
||||
}
|
||||
@@ -56,25 +97,29 @@ api::WifiCapability &NetworkManagerWifiMedium::GetCapability() {
|
||||
}
|
||||
|
||||
api::WifiInformation &NetworkManagerWifiMedium::GetInformation() {
|
||||
{
|
||||
absl::ReaderMutexLock l(&active_access_point_lock_);
|
||||
if (!active_access_point_.has_value()) {
|
||||
std::unique_ptr<NetworkManagerAccessPoint> active_access_point;
|
||||
|
||||
try {
|
||||
auto ap_path = ActiveAccessPoint();
|
||||
if (ap_path.empty()) {
|
||||
information_ = api::WifiInformation{false};
|
||||
return information_;
|
||||
}
|
||||
active_access_point = std::make_unique<NetworkManagerAccessPoint>(
|
||||
getProxy().getConnection(), ap_path);
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_PROPERTY_GET_ERROR(this, "ActiveAccessPoint", e);
|
||||
}
|
||||
try {
|
||||
absl::MutexLock l(&active_access_point_lock_);
|
||||
|
||||
auto ssid_vec = active_access_point_->Ssid();
|
||||
try {
|
||||
auto ssid_vec = active_access_point->Ssid();
|
||||
std::string ssid{ssid_vec.begin(), ssid_vec.end()};
|
||||
|
||||
information_ =
|
||||
api::WifiInformation{true, ssid, active_access_point_->HwAddress(),
|
||||
(int32_t)(active_access_point_->Frequency())};
|
||||
api::WifiInformation{true, ssid, active_access_point->HwAddress(),
|
||||
(int32_t)(active_access_point->Frequency())};
|
||||
NetworkManagerObjectManager manager(getProxy().getConnection());
|
||||
auto ip4config =
|
||||
manager.GetIp4Config(active_access_point_->getObjectPath());
|
||||
auto ip4config = manager.GetIp4Config(active_access_point->getObjectPath());
|
||||
|
||||
if (ip4config != nullptr) {
|
||||
auto address_data = ip4config->AddressData();
|
||||
@@ -90,17 +135,16 @@ api::WifiInformation &NetworkManagerWifiMedium::GetInformation() {
|
||||
information_.ip_address_4_bytes = std::string(addr_bytes, 4);
|
||||
}
|
||||
} else {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath()
|
||||
<< ": Could not find the Ip4Config object for "
|
||||
<< active_access_point_->getObjectPath();
|
||||
<< active_access_point->getObjectPath();
|
||||
}
|
||||
} catch (const sdbus::Error &e) {
|
||||
absl::ReaderMutexLock l(&active_access_point_lock_);
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__ << ": Got error '" << e.getName() << "' with message '"
|
||||
<< e.getMessage()
|
||||
<< __func__ << ": " << getObjectPath() << ": Got error '" << e.getName()
|
||||
<< "' with message '" << e.getMessage()
|
||||
<< "' while populating network information for access point "
|
||||
<< active_access_point_->getObjectPath();
|
||||
<< active_access_point->getObjectPath();
|
||||
}
|
||||
|
||||
return information_;
|
||||
@@ -115,8 +159,12 @@ void NetworkManagerWifiMedium::onPropertiesChanged(
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &[property, _val] : changedProperties) {
|
||||
for (auto &[property, val] : changedProperties) {
|
||||
if (property == "LastScan") {
|
||||
{
|
||||
absl::MutexLock l(&last_scan_lock_);
|
||||
last_scan_ = val;
|
||||
}
|
||||
absl::ReaderMutexLock l(&scan_result_callback_lock_);
|
||||
if (scan_result_callback_.has_value()) {
|
||||
// scan_result_callback_->get().OnScanResults()
|
||||
@@ -140,23 +188,181 @@ bool NetworkManagerWifiMedium::Scan(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkManagerAccessPoint>
|
||||
NetworkManagerWifiMedium::SearchBySSIDNoScan(
|
||||
std::vector<std::uint8_t> &ssid_bytes) {
|
||||
absl::ReaderMutexLock l(&known_access_points_lock_);
|
||||
for (auto &[object_path, ap] : known_access_points_) {
|
||||
if (ap->Ssid() == ssid_bytes) {
|
||||
return ap;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkManagerAccessPoint>
|
||||
NetworkManagerWifiMedium::SearchBySSID(absl::string_view ssid,
|
||||
absl::Duration scan_timeout) {
|
||||
std::vector<std::uint8_t> ssid_bytes(ssid.begin(), ssid.end());
|
||||
// First, try to see if we already know an AP with this SSID.
|
||||
auto ap = SearchBySSIDNoScan(ssid_bytes);
|
||||
if (ap != nullptr) {
|
||||
return ap;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath() << ": SSID " << ssid
|
||||
<< " not currently known by device " << getObjectPath()
|
||||
<< ", requesting a scan";
|
||||
|
||||
std::int64_t cur_last_scan;
|
||||
{
|
||||
absl::ReaderMutexLock l(&last_scan_lock_);
|
||||
cur_last_scan = last_scan_;
|
||||
}
|
||||
|
||||
// Otherwise, request a Scan first and wait for it to finish.
|
||||
try {
|
||||
RequestScan(
|
||||
{{"ssids", std::vector<std::vector<std::uint8_t>>{ssid_bytes}}});
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(this, "RequestScan", e);
|
||||
}
|
||||
|
||||
auto scan_finish = [cur_last_scan, this]() {
|
||||
this->last_scan_lock_.AssertReaderHeld();
|
||||
return cur_last_scan != this->last_scan_;
|
||||
};
|
||||
|
||||
absl::Condition cond(&scan_finish);
|
||||
bool success = last_scan_lock_.ReaderLockWhenWithTimeout(cond, scan_timeout);
|
||||
last_scan_lock_.ReaderUnlock();
|
||||
|
||||
if (!success) {
|
||||
NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath()
|
||||
<< ": timed out waiting for scan to finish";
|
||||
}
|
||||
|
||||
ap = SearchBySSIDNoScan(ssid_bytes);
|
||||
if (ap == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << __func__ << ": " << getObjectPath()
|
||||
<< ": Couldn't find SSID " << ssid;
|
||||
}
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
static inline std::pair<std::string, std::string>
|
||||
AuthAlgAndKeyMgmt(api::WifiAuthType auth_type) {
|
||||
switch (auth_type) {
|
||||
case api::WifiAuthType::kUnknown:
|
||||
return {"open", "none"};
|
||||
case api::WifiAuthType::kOpen:
|
||||
return {"open", "none"};
|
||||
case api::WifiAuthType::kWpaPsk:
|
||||
return {"shared", "wpa-psk"};
|
||||
case api::WifiAuthType::kWep:
|
||||
return {"none", "wep"};
|
||||
}
|
||||
}
|
||||
|
||||
api::WifiConnectionStatus
|
||||
NetworkManagerWifiMedium::ConnectToNetwork(absl::string_view ssid,
|
||||
absl::string_view password,
|
||||
api::WifiAuthType auth_type) {
|
||||
return api::WifiConnectionStatus::kUnknown;
|
||||
|
||||
auto ap = SearchBySSID(ssid);
|
||||
if (ap == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath()
|
||||
<< ": Couldn't find SSID " << ssid;
|
||||
return api::WifiConnectionStatus::kConnectionFailure;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> ssid_bytes(ssid.begin(), ssid.end());
|
||||
std::string connection_id;
|
||||
|
||||
{
|
||||
sd_id128_t id;
|
||||
if (auto ret = sd_id128_randomize(&id); ret < 0) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": could not generation a connection UUID";
|
||||
return api::WifiConnectionStatus::kUnknown;
|
||||
}
|
||||
connection_id = SD_ID128_TO_UUID_STRING(id);
|
||||
}
|
||||
|
||||
auto [auth_alg, key_mgmt] = AuthAlgAndKeyMgmt(auth_type);
|
||||
|
||||
std::map<std::string, std::map<std::string, sdbus::Variant>>
|
||||
connection_settings{
|
||||
{"connection",
|
||||
std::map<std::string, sdbus::Variant>{
|
||||
{"uuid", connection_id},
|
||||
{"autoconnect", true},
|
||||
{"id", ssid},
|
||||
{"type", "802-11-wireless"},
|
||||
{"zone", "Public"},
|
||||
}},
|
||||
{"802-11-wireless",
|
||||
std::map<std::string, sdbus::Variant>{
|
||||
{"ssid", ssid_bytes},
|
||||
{"mode", "infrastructure"},
|
||||
{"security", "802-11-wireless-security"},
|
||||
{"assigned-mac-address", "random"},
|
||||
}},
|
||||
{"802-11-wireless-security",
|
||||
std::map<std::string, sdbus::Variant>{{"auth-alg", auth_alg},
|
||||
{"key-mgmt", key_mgmt}}}};
|
||||
if (!password.empty()) {
|
||||
connection_settings["802-11-wireless-security"]["psk"] =
|
||||
std::string(password);
|
||||
}
|
||||
|
||||
sdbus::ObjectPath connection_path, active_conn_path;
|
||||
try {
|
||||
auto [cp, acp, _r] = network_manager_->AddAndActivateConnection2(
|
||||
connection_settings, getObjectPath(), ap->getObjectPath(),
|
||||
{{"persist", "volatile"}, {"bind-activation", "dbus-client"}});
|
||||
connection_path = std::move(cp);
|
||||
active_conn_path = std::move(acp);
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(this, "AddAndActivateConnection2", e);
|
||||
return api::WifiConnectionStatus::kUnknown;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": " << getObjectPath()
|
||||
<< ": Added a new connection at " << connection_path;
|
||||
auto active_connection = NetworkManagerActiveConnection(
|
||||
getProxy().getConnection(), active_conn_path);
|
||||
auto [reason, timeout] = active_connection.WaitForConnection();
|
||||
if (timeout) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__ << ": " << getObjectPath()
|
||||
<< ": timed out while waiting for connection " << active_conn_path
|
||||
<< " to be activated, last NMActiveConnectionStateReason: "
|
||||
<< reason.value();
|
||||
return api::WifiConnectionStatus::kUnknown;
|
||||
}
|
||||
|
||||
if (reason.has_value()) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": " << getObjectPath() << ": connection "
|
||||
<< active_conn_path
|
||||
<< " failed to activate, NMActiveConnectionStateReason:"
|
||||
<< *reason;
|
||||
if (*reason == ActiveConnectionStateReason::kStateReasonNoSecrets ||
|
||||
*reason == ActiveConnectionStateReason::kStateReasonLoginFailed)
|
||||
return api::WifiConnectionStatus::kAuthFailure;
|
||||
}
|
||||
|
||||
return api::WifiConnectionStatus::kConnected;
|
||||
}
|
||||
|
||||
bool NetworkManagerWifiMedium::VerifyInternetConnectivity() {
|
||||
auto network_manager_proxy_ = sdbus::createProxy(
|
||||
"org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager");
|
||||
network_manager_proxy_->finishRegistration();
|
||||
|
||||
try {
|
||||
std::uint32_t connectivity = network_manager_.CheckConnectivity();
|
||||
std::uint32_t connectivity = network_manager_->CheckConnectivity();
|
||||
return connectivity == 4; // NM_CONNECTIVITY_FULL
|
||||
} catch (const sdbus::Error &e) {
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_proxy_, "CheckConnectivity", e);
|
||||
DBUS_LOG_METHOD_CALL_ERROR(network_manager_, "CheckConnectivity", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user