fix(network): read AP security flags in WiFi scan and unit-test parseAccessPoint
parseAccessPoint() is extracted from an anonymous namespace so the pure property->AccessPointInfo mapping is testable. getAccessPoints() now reads the Flags/WpaFlags/RsnFlags properties (they were never read, so every network was reported Open and connections lacked a security section) and fixes the double container-enter on the SSID 'ay' read that silently emptied the scan list.
This commit is contained in:
+54
-37
@@ -1,6 +1,7 @@
|
||||
#include "nm_device.h"
|
||||
#include "nm_connection.h"
|
||||
#include "logger/logger.h"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -13,8 +14,9 @@ namespace radiantwave::network {
|
||||
|
||||
// ─── Access Point Helper ───────────────────────────────────────────────
|
||||
|
||||
namespace {
|
||||
|
||||
// Build an AccessPointInfo from raw D-Bus AccessPoint property values (see
|
||||
// nm_device.h). The `ssid` argument carries the raw SSID bytes decoded from
|
||||
// the AccessPoint.Ssid `ay` property as a std::string.
|
||||
AccessPointInfo parseAccessPoint(
|
||||
const std::string& object_path,
|
||||
const std::string& ssid,
|
||||
@@ -36,8 +38,6 @@ AccessPointInfo parseAccessPoint(
|
||||
return ap;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ─── WifiDevice Implementation ─────────────────────────────────────────
|
||||
|
||||
#ifdef __linux__
|
||||
@@ -229,13 +229,40 @@ std::vector<AccessPointInfo> WifiDevice::getAccessPoints() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read a single numeric AccessPoint property. Strength is a byte ("y"),
|
||||
// the security flag properties are uint32 ("u"). Leaves `out` untouched on
|
||||
// failure, so callers can rely on zero-initialized defaults.
|
||||
auto readApProperty = [this](const char* ap_path, const char* prop,
|
||||
const char* type, void* out) {
|
||||
sd_bus_message* prop_msg = nullptr;
|
||||
sd_bus_error prop_error = SD_BUS_ERROR_NULL;
|
||||
int pr = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
ap_path,
|
||||
"org.freedesktop.NetworkManager.AccessPoint",
|
||||
prop,
|
||||
&prop_error,
|
||||
&prop_msg,
|
||||
type
|
||||
);
|
||||
if (pr >= 0 && prop_msg) {
|
||||
if (strcmp(type, "u") == 0) {
|
||||
sd_bus_message_read(prop_msg, "u", static_cast<uint32_t*>(out));
|
||||
} else {
|
||||
sd_bus_message_read(prop_msg, "y", static_cast<uint8_t*>(out));
|
||||
}
|
||||
sd_bus_message_unref(prop_msg);
|
||||
}
|
||||
sd_bus_error_free(&prop_error);
|
||||
return pr >= 0;
|
||||
};
|
||||
|
||||
const char* ap_path = nullptr;
|
||||
while ((r = sd_bus_message_read(msg, "o", &ap_path)) > 0 && ap_path) {
|
||||
// Get AP properties
|
||||
sd_bus_message* ap_msg = nullptr;
|
||||
sd_bus_error ap_error = SD_BUS_ERROR_NULL;
|
||||
|
||||
// Get all properties at once
|
||||
|
||||
r = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
@@ -246,51 +273,41 @@ std::vector<AccessPointInfo> WifiDevice::getAccessPoints() const {
|
||||
&ap_msg,
|
||||
"ay"
|
||||
);
|
||||
|
||||
|
||||
if (r >= 0) {
|
||||
// Read SSID byte array
|
||||
sd_bus_message_enter_container(ap_msg, 'a', "y");
|
||||
// Read the SSID byte array. sd_bus_get_property() already leaves
|
||||
// the message positioned at the array (inside the variant wrapper),
|
||||
// and sd_bus_message_read_array() enters AND exits the array
|
||||
// container itself. Do NOT call sd_bus_message_enter_container()
|
||||
// here first, or the read fails and every network silently drops
|
||||
// out of the scan list (it only ever shows up as an empty page with
|
||||
// no error logs).
|
||||
const uint8_t* ssid_data = nullptr;
|
||||
size_t ssid_len = 0;
|
||||
r = sd_bus_message_read_array(ap_msg, 'y', (const void**)&ssid_data, &ssid_len);
|
||||
|
||||
|
||||
std::string ssid;
|
||||
if (r >= 0 && ssid_data && ssid_len > 0) {
|
||||
ssid = std::string(reinterpret_cast<const char*>(ssid_data), ssid_len);
|
||||
}
|
||||
sd_bus_message_unref(ap_msg);
|
||||
|
||||
// Get signal strength
|
||||
sd_bus_message* sig_msg = nullptr;
|
||||
sd_bus_error sig_error = SD_BUS_ERROR_NULL;
|
||||
|
||||
// Remaining properties: signal strength plus the three flags that
|
||||
// drive detectSecurityType() (otherwise every network is reported
|
||||
// as Open and secured connections are built without a security
|
||||
// section).
|
||||
uint8_t signal = 0;
|
||||
|
||||
r = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
ap_path,
|
||||
"org.freedesktop.NetworkManager.AccessPoint",
|
||||
"Strength",
|
||||
&sig_error,
|
||||
&sig_msg,
|
||||
"y"
|
||||
);
|
||||
|
||||
if (r >= 0) {
|
||||
sd_bus_message_read(sig_msg, "y", &signal);
|
||||
sd_bus_message_unref(sig_msg);
|
||||
}
|
||||
sd_bus_error_free(&sig_error);
|
||||
|
||||
// Get flags
|
||||
uint32_t flags = 0, wpa_flags = 0, rsn_flags = 0;
|
||||
// ... (would need similar property reads for flags)
|
||||
|
||||
readApProperty(ap_path, "Strength", "y", &signal);
|
||||
readApProperty(ap_path, "Flags", "u", &flags);
|
||||
readApProperty(ap_path, "WpaFlags", "u", &wpa_flags);
|
||||
readApProperty(ap_path, "RsnFlags", "u", &rsn_flags);
|
||||
|
||||
if (!ssid.empty()) {
|
||||
result.push_back(parseAccessPoint(ap_path, ssid, signal, flags, wpa_flags, rsn_flags));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sd_bus_error_free(&ap_error);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user