Wifi (Linux): implement libnm stuff with plain dbus calls

This commit is contained in:
Carter Li
2024-08-03 22:06:37 +08:00
parent 493cf8ff6c
commit 3a61b31e0a
+129 -15
View File
@@ -1,4 +1,5 @@
#include "wifi.h"
#include "common/dbus.h"
#include "common/processing.h"
#include "common/properties.h"
#include "util/stringUtils.h"
@@ -6,6 +7,118 @@
#include <stdio.h>
#include <stdlib.h>
// https://people.freedesktop.org/~lkundrak/nm-docs/nm-dbus-types.html#NM80211ApFlags
typedef enum {
NM_802_11_AP_FLAGS_NONE = 0x00000000,
NM_802_11_AP_FLAGS_PRIVACY = 0x00000001,
NM_802_11_AP_FLAGS_WPS = 0x00000002,
NM_802_11_AP_FLAGS_WPS_PBC = 0x00000004,
NM_802_11_AP_FLAGS_WPS_PIN = 0x00000008,
} NM80211ApFlags;
// https://people.freedesktop.org/~lkundrak/nm-docs/nm-dbus-types.html#NM80211ApSecurityFlags
typedef enum {
NM_802_11_AP_SEC_NONE = 0x00000000,
NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001,
NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002,
NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004,
NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008,
NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010,
NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020,
NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040,
NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080,
NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100,
NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200,
NM_802_11_AP_SEC_KEY_MGMT_SAE = 0x00000400,
NM_802_11_AP_SEC_KEY_MGMT_OWE = 0x00000800,
NM_802_11_AP_SEC_KEY_MGMT_OWE_TM = 0x00001000,
NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 = 0x00002000,
} NM80211ApSecurityFlags;
static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer)
{
FFDBusData dbus;
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
if(error)
return error;
{
DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars);
if(!device)
return "Failed to call GetDeviceByIpIface";
ffStrbufClear(buffer);
DBusMessageIter rootIter;
if(!dbus.lib->ffdbus_message_iter_init(device, &rootIter) || !ffDBusGetString(&dbus, &rootIter, buffer))
{
dbus.lib->ffdbus_message_unref(device);
return "Failed to get device path";
}
dbus.lib->ffdbus_message_unref(device);
}
if (item->conn.txRate != item->conn.txRate)
{
uint32_t bitrate;
if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "Bitrate", &bitrate))
item->conn.txRate = bitrate / 1000.;
}
FF_STRBUF_AUTO_DESTROY apPath = ffStrbufCreate();
if (!ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", buffer->chars, "org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint", &apPath))
return "Failed to get active access point path";
if (!item->conn.status.length)
ffStrbufSetStatic(&item->conn.status, "connected");
if (!item->conn.ssid.length)
ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Ssid", &item->conn.ssid);
if (!item->conn.bssid.length)
ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "HwAddress", &item->conn.bssid);
if (item->conn.signalQuality != item->conn.signalQuality)
{
uint32_t strengthPercent;
if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Strength", &strengthPercent))
item->conn.signalQuality = strengthPercent;
}
NM80211ApFlags flags;
NM80211ApSecurityFlags wpaFlags, rsnFlags;
if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Flags", &flags) &&
ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "WpaFlags", &wpaFlags) &&
ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars , "org.freedesktop.NetworkManager.AccessPoint", "RsnFlags", &rsnFlags))
{
if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags == NM_802_11_AP_SEC_NONE)
&& (rsnFlags == NM_802_11_AP_SEC_NONE))
ffStrbufAppendS(&item->conn.security, "WEP/");
if (wpaFlags != NM_802_11_AP_SEC_NONE)
ffStrbufAppendS(&item->conn.security, "WPA/");
if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
ffStrbufAppendS(&item->conn.security, "WPA2/");
}
if (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
ffStrbufAppendS(&item->conn.security, "WPA3/");
}
if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) {
ffStrbufAppendS(&item->conn.security, "OWE/");
}
if ((wpaFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
ffStrbufAppendS(&item->conn.security, "802.1X/");
}
if (!item->conn.security.length)
ffStrbufAppendS(&item->conn.security, "Insecure");
else
ffStrbufTrimRight(&item->conn.security, '/');
}
return NULL;
}
static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer)
{
const char* error = NULL;
@@ -28,9 +141,9 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer)
return NULL;
}
ffStrbufAppendS(&item->conn.status, "connected");
ffStrbufSubstrBeforeFirstC(&item->conn.bssid, ' ');
ffStrbufUpperCase(&item->conn.bssid);
ffParsePropLines(output.chars, "SSID: ", &item->conn.ssid);
@@ -63,8 +176,6 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer)
}
#if FF_HAVE_LINUX_WIRELESS
#define FF_DETECT_WIFI_WITH_IOCTLS
#include "common/io/io.h"
#include <net/if.h>
@@ -86,7 +197,10 @@ static const char* detectWifiWithIoctls(FFWifiResult* item)
iwr.u.essid.length = IW_ESSID_MAX_SIZE + 1;
iwr.u.essid.flags = 0;
if(ioctl(sock, SIOCGIWESSID, &iwr) >= 0)
{
ffStrbufSetStatic(&item->conn.status, "connected");
ffStrbufRecalculateLength(&item->conn.ssid);
}
if(ioctl(sock, SIOCGIWNAME, &iwr) >= 0 && !ffStrEqualsIgnCase(iwr.u.name, "IEEE 802.11"))
{
@@ -99,10 +213,13 @@ static const char* detectWifiWithIoctls(FFWifiResult* item)
if(ioctl(sock, SIOCGIWAP, &iwr) >= 0)
{
for(int i = 0; i < 6; ++i)
ffStrbufAppendF(&item->conn.bssid, "%.2X-", (uint8_t) iwr.u.ap_addr.sa_data[i]);
ffStrbufAppendF(&item->conn.bssid, "%.2X:", (uint8_t) iwr.u.ap_addr.sa_data[i]);
ffStrbufTrimRight(&item->conn.bssid, '-');
}
if(ioctl(sock, SIOCGIWRATE, &iwr) >= 0)
item->conn.txRate = iwr.u.bitrate.value / 1000000.;
struct iw_statistics stats;
iwr.u.data.pointer = &stats;
iwr.u.data.length = sizeof(stats);
@@ -156,7 +273,6 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result)
return "if_nameindex() failed";
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = NULL;
for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i)
{
@@ -184,18 +300,16 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result)
if (!ffStrbufEqualS(&item->inf.status, "up"))
continue;
if (detectWifiWithIw(item, &buffer) == NULL)
continue;
if (detectWifiWithIw(item, &buffer) != NULL)
{
#ifdef FF_HAVE_LINUX_WIRELESS
detectWifiWithIoctls(item);
#endif
}
#ifdef FF_DETECT_WIFI_WITH_IOCTLS
detectWifiWithIoctls(item);
continue;
#endif
error = "`iw` failed and `linux/wireless.h` not found during compilation";
break;
detectWifiWithNm(item, &buffer);
}
if_freenameindex(infs);
return error;
return NULL;
}