summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-10-22 16:58:40 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2020-10-22 16:58:40 +0200
commit880fe31ef284ce7fee77694df2eb0448e17aeb8a (patch)
tree2e20d6c9baa6cf64ebf7619aa715bad405d6ce9b
parentcc030b9112d2fd474a64e4356d4bc42b017eff13 (diff)
parentada71a4af6af7f2e830f266e757aabfe2e5dcabb (diff)
wifi: merge branch 'balrog-kun/NetworkManager-iwd-query-speed'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/652
-rw-r--r--src/devices/wifi/nm-device-iwd.c82
-rw-r--r--src/platform/wifi/nm-wifi-utils-nl80211.c286
2 files changed, 172 insertions, 196 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index 15c1191701..c479b3d453 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -54,6 +54,7 @@ typedef struct {
NMDeviceWifiCapabilities capabilities;
NMActRequestGetSecretsCallId *wifi_secrets_id;
guint periodic_scan_id;
+ guint periodic_update_id;
bool enabled : 1;
bool can_scan : 1;
bool can_connect : 1;
@@ -65,6 +66,8 @@ typedef struct {
bool networks_changed : 1;
gint64 last_scan;
uint32_t ap_id;
+ guint32 rate;
+ uint8_t current_ap_bssid[ETH_ALEN];
} NMDeviceIwdPrivate;
struct _NMDeviceIwd {
@@ -163,6 +166,7 @@ set_current_ap(NMDeviceIwd *self, NMWifiAP *new_ap, gboolean recheck_available_c
g_object_unref(old_ap);
}
+ memset(priv->current_ap_bssid, 0, ETH_ALEN);
_notify(self, PROP_ACTIVE_ACCESS_POINT);
_notify(self, PROP_MODE);
schedule_periodic_scan(self, TRUE);
@@ -177,8 +181,6 @@ remove_all_aps(NMDeviceIwd *self)
if (c_list_is_empty(&priv->aps_lst_head))
return;
- set_current_ap(self, NULL, FALSE);
-
c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst)
ap_add_remove(self, FALSE, ap, FALSE);
@@ -404,6 +406,63 @@ update_aps(NMDeviceIwd *self)
}
static void
+periodic_update(NMDeviceIwd *self)
+{
+ NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
+ int ifindex;
+ guint32 new_rate;
+ int percent;
+ guint8 bssid[ETH_ALEN];
+ gboolean ap_changed = FALSE;
+ NMPlatform * platform;
+
+ ifindex = nm_device_get_ifindex(NM_DEVICE(self));
+ if (ifindex <= 0)
+ g_return_if_reached();
+
+ platform = nm_device_get_platform(NM_DEVICE(self));
+
+ /* TODO: obtain this through the net.connman.iwd.SignalLevelAgent API.
+ * For now we're waking up for the rate updates anyway.
+ */
+ percent = nm_platform_wifi_get_quality(platform, ifindex);
+ if (percent >= 0 && percent <= 100) {
+ if (nm_wifi_ap_set_strength(priv->current_ap, (gint8) percent)) {
+#if NM_MORE_LOGGING
+ ap_changed = TRUE;
+#endif
+ }
+ }
+
+ new_rate = nm_platform_wifi_get_rate(platform, ifindex);
+ if (new_rate != priv->rate) {
+ priv->rate = new_rate;
+ _notify(self, PROP_BITRATE);
+ }
+
+ if (nm_platform_wifi_get_bssid(platform, ifindex, bssid)
+ && nm_ethernet_address_is_valid(bssid, ETH_ALEN)
+ && memcmp(bssid, priv->current_ap_bssid, ETH_ALEN)) {
+ gs_free char *bssid_str = NULL;
+ memcpy(priv->current_ap_bssid, bssid, ETH_ALEN);
+ bssid_str = nm_utils_hwaddr_ntoa(bssid, ETH_ALEN);
+ ap_changed |= nm_wifi_ap_set_address(priv->current_ap, bssid_str);
+ ap_changed |= nm_wifi_ap_set_freq(priv->current_ap,
+ nm_platform_wifi_get_frequency(platform, ifindex));
+ }
+
+ if (ap_changed)
+ _ap_dump(self, LOGL_DEBUG, priv->current_ap, "updated");
+}
+
+static gboolean
+periodic_update_cb(gpointer user_data)
+{
+ periodic_update(user_data);
+ return TRUE;
+}
+
+static void
send_disconnect(NMDeviceIwd *self)
{
NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self);
@@ -436,6 +495,7 @@ cleanup_association_attempt(NMDeviceIwd *self, gboolean disconnect)
wifi_secrets_cancel(self);
set_current_ap(self, NULL, TRUE);
+ nm_clear_g_source(&priv->periodic_update_id);
if (disconnect && priv->dbus_station_proxy)
send_disconnect(self);
@@ -1450,6 +1510,11 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data)
ssid_utf8);
nm_device_activate_schedule_stage3_ip_config_start(device);
+ if (!priv->periodic_update_id) {
+ priv->periodic_update_id = g_timeout_add_seconds(6, periodic_update_cb, self);
+ periodic_update(self);
+ }
+
return;
failed:
@@ -1499,11 +1564,12 @@ act_start_cb(GObject *source, GAsyncResult *res, gpointer user_data)
NMSettingWireless * s_wireless;
GBytes * ssid;
gs_free char * ssid_utf8 = NULL;
+ const char * mode;
variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error);
if (!variant) {
_LOGE(LOGD_DEVICE | LOGD_WIFI,
- "Activation: (wifi) Network.Connect failed: %s",
+ "Activation: (wifi) {AccessPoint,AdHoc}.Start() failed: %s",
error->message);
if (nm_utils_error_is_cancelled(error))
@@ -1530,8 +1596,14 @@ act_start_cb(GObject *source, GAsyncResult *res, gpointer user_data)
_LOGI(LOGD_DEVICE | LOGD_WIFI,
"Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Started '%s'.",
ssid_utf8);
-
nm_device_activate_schedule_stage3_ip_config_start(device);
+
+ mode = nm_setting_wireless_get_mode(s_wireless);
+ if (!priv->periodic_update_id && nm_streq0(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
+ priv->periodic_update_id = g_timeout_add_seconds(6, periodic_update_cb, self);
+ periodic_update(self);
+ }
+
return;
error:
@@ -2153,7 +2225,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
break;
case PROP_BITRATE:
- g_value_set_uint(value, 65000);
+ g_value_set_uint(value, priv->rate);
break;
case PROP_CAPABILITIES:
g_value_set_uint(value, priv->capabilities);
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c
index dddfa8fafb..13f8f5bf1a 100644
--- a/src/platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/platform/wifi/nm-wifi-utils-nl80211.c
@@ -41,6 +41,16 @@
} \
G_STMT_END
+struct nl80211_station_info {
+ gboolean valid;
+ guint8 bssid[ETH_ALEN];
+ guint32 txrate;
+ gboolean txrate_valid;
+ guint8 signal;
+ gboolean signal_valid;
+ gint64 timestamp;
+};
+
typedef struct {
NMWifiUtils parent;
struct nl_sock *nl_sock;
@@ -49,6 +59,8 @@ typedef struct {
int num_freqs;
int phy;
bool can_wowlan : 1;
+
+ struct nl80211_station_info sta_info;
} NMWifiUtilsNl80211;
typedef struct {
@@ -163,6 +175,7 @@ dispose(GObject *object)
struct nl80211_iface_info {
NM80211Mode mode;
+ uint32_t freq;
};
static int
@@ -193,6 +206,9 @@ nl80211_iface_info_handler(struct nl_msg *msg, void *arg)
break;
}
+ if (tb[NL80211_ATTR_WIPHY_FREQ] != NULL)
+ info->freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+
return NL_SKIP;
}
@@ -359,142 +375,19 @@ nla_put_failure:
g_return_val_if_reached(FALSE);
}
-/* @divisor: pass what value @xbm should be divided by to get dBm */
-static guint32
-nl80211_xbm_to_percent(gint32 xbm, guint32 divisor)
-{
-#define NOISE_FLOOR_DBM -90
-#define SIGNAL_MAX_DBM -20
-
- xbm /= divisor;
- xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
-
- return 100
- - 70
- * (((float) SIGNAL_MAX_DBM - (float) xbm)
- / ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM));
-}
-
-struct nl80211_bss_info {
- guint32 freq;
- guint8 bssid[ETH_ALEN];
- guint8 ssid[32];
- guint32 ssid_len;
- guint32 beacon_signal;
- gboolean valid;
-};
-
-#define WLAN_EID_SSID 0
-
-static void
-find_ssid(guint8 *ies, guint32 ies_len, guint8 **ssid, guint32 *ssid_len)
-{
- *ssid = NULL;
- *ssid_len = 0;
-
- while (ies_len > 2 && ies[0] != WLAN_EID_SSID) {
- ies_len -= ies[1] + 2;
- ies += ies[1] + 2;
- }
- if (ies_len < 2)
- return;
- if (ies_len < 2 + ies[1])
- return;
-
- *ssid_len = ies[1];
- *ssid = ies + 2;
-}
-
-static int
-nl80211_bss_dump_handler(struct nl_msg *msg, void *arg)
-{
- static const struct nla_policy bss_policy[] = {
- [NL80211_BSS_TSF] = {.type = NLA_U64},
- [NL80211_BSS_FREQUENCY] = {.type = NLA_U32},
- [NL80211_BSS_BSSID] = {.minlen = ETH_ALEN},
- [NL80211_BSS_BEACON_INTERVAL] = {.type = NLA_U16},
- [NL80211_BSS_CAPABILITY] = {.type = NLA_U16},
- [NL80211_BSS_INFORMATION_ELEMENTS] = {},
- [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
- [NL80211_BSS_SIGNAL_UNSPEC] = {.type = NLA_U8},
- [NL80211_BSS_STATUS] = {.type = NLA_U32},
- };
- struct nl80211_bss_info *info = arg;
- struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr * tb[NL80211_ATTR_MAX + 1];
- struct nlattr * bss[G_N_ELEMENTS(bss_policy)];
- guint32 status;
-
- if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
- return NL_SKIP;
-
- if (tb[NL80211_ATTR_BSS] == NULL)
- return NL_SKIP;
-
- if (nla_parse_nested_arr(bss, tb[NL80211_ATTR_BSS], bss_policy))
- return NL_SKIP;
-
- if (bss[NL80211_BSS_STATUS] == NULL)
- return NL_SKIP;
-
- status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-
- if (status != NL80211_BSS_STATUS_ASSOCIATED && status != NL80211_BSS_STATUS_IBSS_JOINED)
- return NL_SKIP;
-
- if (bss[NL80211_BSS_BSSID] == NULL)
- return NL_SKIP;
- memcpy(info->bssid, nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
-
- if (bss[NL80211_BSS_FREQUENCY])
- info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-
- if (bss[NL80211_BSS_SIGNAL_UNSPEC])
- info->beacon_signal = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-
- if (bss[NL80211_BSS_SIGNAL_MBM])
- info->beacon_signal = nl80211_xbm_to_percent(nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]), 100);
-
- if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
- guint8 *ssid;
- guint32 ssid_len;
-
- find_ssid(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
- nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
- &ssid,
- &ssid_len);
- if (ssid && ssid_len && ssid_len <= sizeof(info->ssid)) {
- memcpy(info->ssid, ssid, ssid_len);
- info->ssid_len = ssid_len;
- }
- }
-
- info->valid = TRUE;
-
- return NL_SKIP;
-}
-
-static void
-nl80211_get_bss_info(NMWifiUtilsNl80211 *self, struct nl80211_bss_info *bss_info)
-{
- nm_auto_nlmsg struct nl_msg *msg = NULL;
-
- memset(bss_info, 0, sizeof(*bss_info));
-
- msg = nl80211_alloc_msg(self, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
-
- nl80211_send_and_recv(self, msg, nl80211_bss_dump_handler, bss_info);
-}
-
static guint32
wifi_nl80211_get_freq(NMWifiUtils *data)
{
- NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data;
- struct nl80211_bss_info bss_info;
+ NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data;
+ struct nl80211_iface_info iface_info = {};
+ nm_auto_nlmsg struct nl_msg *msg = NULL;
- nl80211_get_bss_info(self, &bss_info);
+ msg = nl80211_alloc_msg(self, NL80211_CMD_GET_INTERFACE, 0);
- return bss_info.freq;
+ if (nl80211_send_and_recv(self, msg, nl80211_iface_info_handler, &iface_info) < 0)
+ return 0;
+
+ return iface_info.freq;
}
static guint32
@@ -513,41 +406,38 @@ wifi_nl80211_find_freq(NMWifiUtils *data, const guint32 *freqs)
return 0;
}
-static gboolean
-wifi_nl80211_get_bssid(NMWifiUtils *data, guint8 *out_bssid)
+/* @divisor: pass what value @xbm should be divided by to get dBm */
+static guint32
+nl80211_xbm_to_percent(gint32 xbm, guint32 divisor)
{
- NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data;
- struct nl80211_bss_info bss_info;
-
- nl80211_get_bss_info(self, &bss_info);
+#define NOISE_FLOOR_DBM -90
+#define SIGNAL_MAX_DBM -20
- if (bss_info.valid)
- memcpy(out_bssid, bss_info.bssid, ETH_ALEN);
+ xbm /= divisor;
+ xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
- return bss_info.valid;
+ return 100
+ - 70
+ * (((float) SIGNAL_MAX_DBM - (float) xbm)
+ / ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM));
}
-struct nl80211_station_info {
- guint32 txrate;
- gboolean txrate_valid;
- guint8 signal;
- gboolean signal_valid;
-};
-
static int
-nl80211_station_handler(struct nl_msg *msg, void *arg)
+nl80211_station_dump_handler(struct nl_msg *msg, void *arg)
{
static const struct nla_policy stats_policy[] = {
- [NL80211_STA_INFO_INACTIVE_TIME] = {.type = NLA_U32},
- [NL80211_STA_INFO_RX_BYTES] = {.type = NLA_U32},
- [NL80211_STA_INFO_TX_BYTES] = {.type = NLA_U32},
- [NL80211_STA_INFO_RX_PACKETS] = {.type = NLA_U32},
- [NL80211_STA_INFO_TX_PACKETS] = {.type = NLA_U32},
- [NL80211_STA_INFO_SIGNAL] = {.type = NLA_U8},
- [NL80211_STA_INFO_TX_BITRATE] = {.type = NLA_NESTED},
- [NL80211_STA_INFO_LLID] = {.type = NLA_U16},
- [NL80211_STA_INFO_PLID] = {.type = NLA_U16},
- [NL80211_STA_INFO_PLINK_STATE] = {.type = NLA_U8},
+ [NL80211_STA_INFO_INACTIVE_TIME] = {.type = NLA_U32},
+ [NL80211_STA_INFO_RX_BYTES] = {.type = NLA_U32},
+ [NL80211_STA_INFO_TX_BYTES] = {.type = NLA_U32},
+ [NL80211_STA_INFO_RX_PACKETS] = {.type = NLA_U32},
+ [NL80211_STA_INFO_TX_PACKETS] = {.type = NLA_U32},
+ [NL80211_STA_INFO_SIGNAL] = {.type = NLA_U8},
+ [NL80211_STA_INFO_TX_BITRATE] = {.type = NLA_NESTED},
+ [NL80211_STA_INFO_LLID] = {.type = NLA_U16},
+ [NL80211_STA_INFO_PLID] = {.type = NLA_U16},
+ [NL80211_STA_INFO_PLINK_STATE] = {.type = NLA_U8},
+ [NL80211_STA_INFO_STA_FLAGS] = {.minlen = sizeof(struct nl80211_sta_flag_update)},
+ [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = {.type = NLA_U8},
};
static const struct nla_policy rate_policy[] = {
[NL80211_RATE_INFO_BITRATE] = {.type = NLA_U16},
@@ -564,80 +454,94 @@ nl80211_station_handler(struct nl_msg *msg, void *arg)
if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
return NL_SKIP;
+ if (tb[NL80211_ATTR_MAC] == NULL)
+ return NL_SKIP;
+
if (tb[NL80211_ATTR_STA_INFO] == NULL)
return NL_SKIP;
if (nla_parse_nested_arr(sinfo, tb[NL80211_ATTR_STA_INFO], stats_policy))
return NL_SKIP;
- if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL)
- return NL_SKIP;
+ if (sinfo[NL80211_STA_INFO_STA_FLAGS] != NULL) {
+ const struct nl80211_sta_flag_update *flags = nla_data(sinfo[NL80211_STA_INFO_STA_FLAGS]);
- if (nla_parse_nested_arr(rinfo, sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
- return NL_SKIP;
+ if (flags->mask & ~flags->set & (1 << NL80211_STA_FLAG_ASSOCIATED))
+ return NL_SKIP;
+ }
- if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL)
- return NL_SKIP;
+ memcpy(info->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+ info->valid = TRUE;
- /* convert from nl80211's units of 100kbps to NM's kbps */
- info->txrate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
- info->txrate_valid = TRUE;
+ if (sinfo[NL80211_STA_INFO_TX_BITRATE] != NULL
+ && !nla_parse_nested_arr(rinfo, sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy)
+ && rinfo[NL80211_RATE_INFO_BITRATE] != NULL) {
+ /* convert from nl80211's units of 100kbps to NM's kbps */
+ info->txrate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
+ info->txrate_valid = TRUE;
+ }
if (sinfo[NL80211_STA_INFO_SIGNAL] != NULL) {
info->signal =
nl80211_xbm_to_percent((gint8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]), 1);
info->signal_valid = TRUE;
+ } else if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG] != NULL) {
+ /* Fall back to beacon signal strength */
+ info->signal =
+ nl80211_xbm_to_percent((gint8) nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]), 1);
+ info->signal_valid = TRUE;
}
return NL_SKIP;
}
static void
-nl80211_get_ap_info(NMWifiUtilsNl80211 *self, struct nl80211_station_info *sta_info)
+nl80211_get_sta_info(NMWifiUtilsNl80211 *self)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
- struct nl80211_bss_info bss_info;
-
- memset(sta_info, 0, sizeof(*sta_info));
+ gint64 now = nm_utils_get_monotonic_timestamp_msec();
- nl80211_get_bss_info(self, &bss_info);
- if (!bss_info.valid)
+ if (self->sta_info.valid && now - self->sta_info.timestamp < 500)
return;
- msg = nl80211_alloc_msg(self, NL80211_CMD_GET_STATION, 0);
- NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bss_info.bssid);
+ memset(&self->sta_info, 0, sizeof(self->sta_info));
- nl80211_send_and_recv(self, msg, nl80211_station_handler, sta_info);
- if (!sta_info->signal_valid) {
- /* Fall back to bss_info signal quality (both are in percent) */
- sta_info->signal = bss_info.beacon_signal;
- }
+ msg = nl80211_alloc_msg(self, NL80211_CMD_GET_STATION, NLM_F_DUMP);
- return;
+ nl80211_send_and_recv(self, msg, nl80211_station_dump_handler, &self->sta_info);
+ self->sta_info.timestamp = now;
+}
-nla_put_failure:
- g_return_if_reached();
+static gboolean
+wifi_nl80211_get_bssid(NMWifiUtils *data, guint8 *out_bssid)
+{
+ NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
+
+ nl80211_get_sta_info(self);
+
+ if (self->sta_info.valid)
+ memcpy(out_bssid, self->sta_info.bssid, ETH_ALEN);
+
+ return self->sta_info.valid;
}
static guint32
wifi_nl80211_get_rate(NMWifiUtils *data)
{
- NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data;
- struct nl80211_station_info sta_info;
+ NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
- nl80211_get_ap_info(self, &sta_info);
+ nl80211_get_sta_info(self);
- return sta_info.txrate;
+ return self->sta_info.txrate;
}
static int
wifi_nl80211_get_qual(NMWifiUtils *data)
{
- NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data;
- struct nl80211_station_info sta_info;
+ NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data;
- nl80211_get_ap_info(self, &sta_info);
- return sta_info.signal;
+ nl80211_get_sta_info(self);
+ return self->sta_info.signal;
}
static gboolean