diff options
Diffstat (limited to 'src/devices/wifi')
| -rw-r--r-- | src/devices/wifi/meson.build | 46 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-iwd.c | 248 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-iwd.h | 2 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-olpc-mesh.c | 53 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi-p2p.c | 187 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 782 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.h | 9 | ||||
| -rw-r--r-- | src/devices/wifi/nm-iwd-manager.c | 3 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.c | 651 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.h | 26 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-factory.c | 4 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-p2p-peer.c | 221 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-p2p-peer.h | 11 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-utils.c | 25 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-utils.h | 2 | ||||
| -rw-r--r-- | src/devices/wifi/tests/test-devices-wifi.c | 57 |
16 files changed, 899 insertions, 1428 deletions
diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build index 6566f201..00404c71 100644 --- a/src/devices/wifi/meson.build +++ b/src/devices/wifi/meson.build @@ -1,28 +1,38 @@ -common_sources = files( - 'nm-wifi-ap.c', - 'nm-wifi-p2p-peer.c', - 'nm-wifi-utils.c', -) - -sources = common_sources + files( - 'nm-device-olpc-mesh.c', - 'nm-device-wifi-p2p.c', - 'nm-device-wifi.c', - 'nm-wifi-common.c', - 'nm-wifi-factory.c', -) +# SPDX-License-Identifier: LGPL-2.1+ +iwd_sources = files() if enable_iwd - sources += files( + iwd_sources += files( 'nm-device-iwd.c', 'nm-iwd-manager.c', ) endif +libnm_wifi_base = static_library( + 'nm-wifi-base', + sources: files( + 'nm-device-olpc-mesh.c', + 'nm-device-wifi-p2p.c', + 'nm-device-wifi.c', + 'nm-wifi-ap.c', + 'nm-wifi-common.c', + 'nm-wifi-p2p-peer.c', + 'nm-wifi-utils.c', + ) + iwd_sources, + dependencies: daemon_nm_default_dep, + c_args: daemon_c_flags, +) + +libnm_wifi_base_dep = declare_dependency( + link_with: libnm_wifi_base, +) + libnm_device_plugin_wifi = shared_module( 'nm-device-plugin-wifi', - sources: sources, - dependencies: daemon_nm_default_dep, + sources: files( + 'nm-wifi-factory.c', + ), + dependencies: [ daemon_nm_default_dep, libnm_wifi_base_dep ], c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, @@ -43,8 +53,8 @@ if enable_tests exe = executable( test_unit, - ['tests/' + test_unit + '.c'] + common_sources, - dependencies: libnetwork_manager_test_dep, + 'tests/' + test_unit + '.c', + dependencies: [ libnetwork_manager_test_dep, libnm_wifi_base_dep ], c_args: test_c_flags, ) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 6b587e3f..3c1d5b22 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -7,24 +7,26 @@ #include "nm-device-iwd.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "devices/nm-device.h" #include "devices/nm-device-private.h" -#include "nm-utils.h" +#include "devices/nm-device.h" #include "nm-act-request.h" +#include "nm-config.h" +#include "nm-core-internal.h" +#include "nm-dbus-manager.h" +#include "nm-glib-aux/nm-ref-string.h" +#include "nm-iwd-manager.h" +#include "nm-libnm-core-intern/nm-common-macros.h" +#include "nm-setting-8021x.h" #include "nm-setting-connection.h" -#include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" -#include "nm-setting-8021x.h" +#include "nm-setting-wireless.h" +#include "nm-std-aux/nm-dbus-compat.h" +#include "nm-utils.h" +#include "nm-wifi-common.h" +#include "nm-wifi-utils.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" -#include "nm-wifi-utils.h" -#include "nm-wifi-common.h" -#include "nm-core-internal.h" -#include "nm-config.h" -#include "nm-iwd-manager.h" -#include "nm-dbus-manager.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "supplicant/nm-supplicant-types.h" #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceIwd); @@ -41,14 +43,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceIwd, PROP_LAST_SCAN, ); -enum { - SCANNING_PROHIBITED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - typedef struct { GDBusObject * dbus_obj; GDBusProxy * dbus_device_proxy; @@ -77,37 +71,35 @@ struct _NMDeviceIwd { struct _NMDeviceIwdClass { NMDeviceClass parent; - - /* Signals */ - gboolean (*scanning_prohibited) (NMDeviceIwd *device, gboolean periodic); }; /*****************************************************************************/ G_DEFINE_TYPE (NMDeviceIwd, nm_device_iwd, NM_TYPE_DEVICE) -#define NM_DEVICE_IWD_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceIwd, NM_IS_DEVICE_IWD) +#define NM_DEVICE_IWD_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceIwd, NM_IS_DEVICE_IWD, NMDevice) /*****************************************************************************/ static void schedule_periodic_scan (NMDeviceIwd *self, gboolean initial_scan); +static gboolean check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic); + /*****************************************************************************/ static void _ap_dump (NMDeviceIwd *self, NMLogLevel log_level, const NMWifiAP *ap, - const char *prefix, - gint32 now_s) + const char *prefix) { char buf[1024]; buf[0] = '\0'; _NMLOG (log_level, LOGD_WIFI_SCAN, "wifi-ap: %-7s %s", prefix, - nm_wifi_ap_to_string (ap, buf, sizeof (buf), now_s)); + nm_wifi_ap_to_string (ap, buf, sizeof (buf), 0)); } /* Callers ensure we're not removing current_ap */ @@ -124,12 +116,12 @@ ap_add_remove (NMDeviceIwd *self, ap->wifi_device = NM_DEVICE (self); c_list_link_tail (&priv->aps_lst_head, &ap->aps_lst); nm_dbus_object_export (NM_DBUS_OBJECT (ap)); - _ap_dump (self, LOGL_DEBUG, ap, "added", 0); + _ap_dump (self, LOGL_DEBUG, ap, "added"); nm_device_wifi_emit_signal_access_point (NM_DEVICE (self), ap, TRUE); } else { ap->wifi_device = NULL; c_list_unlink (&ap->aps_lst); - _ap_dump (self, LOGL_DEBUG, ap, "removed", 0); + _ap_dump (self, LOGL_DEBUG, ap, "removed"); } _notify (self, PROP_ACCESS_POINTS); @@ -191,45 +183,43 @@ remove_all_aps (NMDeviceIwd *self) nm_device_recheck_available_connections (NM_DEVICE (self)); } -static GVariant * -vardict_from_network_type (const char *type) +static NM80211ApSecurityFlags +ap_security_flags_from_network_type (const char *type) { - GVariantBuilder builder; - const char *key_mgmt = ""; - const char *pairwise = "ccmp"; + NM80211ApSecurityFlags flags; - if (!strcmp (type, "psk")) - key_mgmt = "wpa-psk"; - else if (!strcmp (type, "8021x")) - key_mgmt = "wpa-eap"; + if (nm_streq (type, "psk")) + flags = NM_802_11_AP_SEC_KEY_MGMT_PSK; + else if (nm_streq (type, "8021x")) + flags = NM_802_11_AP_SEC_KEY_MGMT_802_1X; else - return NULL; + return NM_802_11_AP_SEC_NONE; - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "KeyMgmt", - g_variant_new_strv (&key_mgmt, 1)); - g_variant_builder_add (&builder, "{sv}", "Pairwise", - g_variant_new_strv (&pairwise, 1)); - g_variant_builder_add (&builder, "{sv}", "Group", - g_variant_new_string ("ccmp")); - return g_variant_new ("a{sv}", &builder); + flags |= NM_802_11_AP_SEC_PAIR_CCMP; + flags |= NM_802_11_AP_SEC_GROUP_CCMP; + return flags; } static void insert_ap_from_network (NMDeviceIwd *self, GHashTable *aps, const char *path, + gint64 last_seen_msec, int16_t signal, uint32_t ap_id) { gs_unref_object GDBusProxy *network_proxy = NULL; - gs_unref_variant GVariant *name_value = NULL, *type_value = NULL; - const char *name, *type; - GVariantBuilder builder; - gs_unref_variant GVariant *props = NULL; - GVariant *rsn; + gs_unref_variant GVariant *name_value = NULL; + gs_unref_variant GVariant *type_value = NULL; + nm_auto_ref_string NMRefString *bss_path = NULL; + const char *name; + const char *type; + NMSupplicantBssInfo bss_info; uint8_t bssid[6]; NMWifiAP *ap; + gs_unref_bytes GBytes *ssid = NULL; + + bss_path = nm_ref_string_new (path); if (g_hash_table_lookup (aps, path)) { _LOGD (LOGD_WIFI, "Duplicate network at %s", path); @@ -253,6 +243,11 @@ insert_ap_from_network (NMDeviceIwd *self, name = g_variant_get_string (name_value, NULL); type = g_variant_get_string (type_value, NULL); + if (nm_streq (type, "wep")) { + /* WEP not supported */ + return; + } + /* What we get from IWD are networks, or ESSs, that may contain * multiple APs, or BSSs, each. We don't get information about any * specific BSSs within an ESS but we can safely present each ESS @@ -268,32 +263,26 @@ insert_ap_from_network (NMDeviceIwd *self, bssid[4] = ap_id >> 8; bssid[5] = ap_id; - /* WEP not supported */ - if (nm_streq (type, "wep")) - return; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "BSSID", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); - g_variant_builder_add (&builder, "{sv}", "Mode", - g_variant_new_string ("infrastructure")); - - rsn = vardict_from_network_type (type); - if (rsn) - g_variant_builder_add (&builder, "{sv}", "RSN", rsn); + ssid = g_bytes_new (name, NM_MIN (32u, strlen (name))); - props = g_variant_new ("a{sv}", &builder); + bss_info = (NMSupplicantBssInfo) { + .bss_path = bss_path, + .last_seen_msec = last_seen_msec, + .bssid_valid = TRUE, + .mode = NM_802_11_MODE_INFRA, + .rsn_flags = ap_security_flags_from_network_type (type), + .ssid = ssid, + .signal_percent = nm_wifi_utils_level_to_quality (signal / 100), + .frequency = 2417, + .max_rate = 65000, + }; + memcpy (bss_info.bssid, bssid, sizeof (bssid)); - ap = nm_wifi_ap_new_from_properties (path, props); + ap = nm_wifi_ap_new_from_properties (&bss_info); - nm_wifi_ap_set_ssid_arr (ap, - (const guint8 *) name, - NM_MIN (32, strlen (name))); + nm_assert (bss_path == nm_wifi_ap_get_supplicant_path (ap)); - nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); - nm_wifi_ap_set_freq (ap, 2417); - nm_wifi_ap_set_max_bitrate (ap, 65000); - g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap); + g_hash_table_insert (aps, bss_path, ap); } static void @@ -313,6 +302,7 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) gboolean compat; const char *return_sig; static uint32_t ap_id = 0; + gint64 last_seen_msec; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); if (!variant) { @@ -336,16 +326,17 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) return; } - new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); + new_aps = g_hash_table_new_full (nm_direct_hash, NULL, NULL, g_object_unref); g_variant_get (variant, return_sig, &networks); + last_seen_msec = nm_utils_get_monotonic_timestamp_msec (); if (compat) { while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) - insert_ap_from_network (self, new_aps, path, signal, ap_id++); + insert_ap_from_network (self, new_aps, path, last_seen_msec, signal, ap_id++); } else { while (g_variant_iter_next (networks, "(&on)", &path, &signal)) - insert_ap_from_network (self, new_aps, path, signal, ap_id++); + insert_ap_from_network (self, new_aps, path, last_seen_msec, signal, ap_id++); } g_variant_iter_free (networks); @@ -356,7 +347,7 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) nm_wifi_ap_get_supplicant_path (ap)); if (new_ap) { if (nm_wifi_ap_set_strength (ap, nm_wifi_ap_get_strength (new_ap))) { - _ap_dump (self, LOGL_TRACE, ap, "updated", 0); + _ap_dump (self, LOGL_TRACE, ap, "updated"); changed = TRUE; } g_hash_table_remove (new_aps, @@ -566,20 +557,17 @@ is_connection_known_network (NMConnection *connection) static gboolean is_ap_known_network (NMWifiAP *ap) { - GDBusProxy *network_proxy; + gs_unref_object GDBusProxy *network_proxy = NULL; gs_unref_variant GVariant *known_network = NULL; network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), - nm_wifi_ap_get_supplicant_path (ap), + nm_ref_string_get_str (nm_wifi_ap_get_supplicant_path (ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) return FALSE; known_network = g_dbus_proxy_get_cached_property (network_proxy, "KnownNetwork"); - g_object_unref (network_proxy); - - return known_network - && g_variant_is_of_type (known_network, G_VARIANT_TYPE_OBJECT_PATH); + return nm_g_variant_is_of_type (known_network, G_VARIANT_TYPE_OBJECT_PATH); } static gboolean @@ -975,15 +963,6 @@ _nm_device_iwd_get_aps (NMDeviceIwd *self) return &NM_DEVICE_IWD_GET_PRIVATE (self)->aps_lst_head; } -static gboolean -check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic) -{ - gboolean prohibited = FALSE; - - g_signal_emit (self, signals[SCANNING_PROHIBITED], 0, periodic, &prohibited); - return prohibited; -} - static void scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -993,12 +972,12 @@ scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) gs_free_error GError *error = NULL; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); - if (!variant && nm_utils_error_is_cancelled (error, FALSE)) + if (!variant && nm_utils_error_is_cancelled (error)) return; priv = NM_DEVICE_IWD_GET_PRIVATE (self); priv->scan_requested = FALSE; - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + priv->last_scan = nm_utils_get_monotonic_timestamp_msec (); _notify (self, PROP_LAST_SCAN); /* On success, priv->scanning becomes true right before or right @@ -1093,7 +1072,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self, } static gboolean -scanning_prohibited (NMDeviceIwd *self, gboolean periodic) +check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -1148,7 +1127,7 @@ try_reply_agent_request (NMDeviceIwd *self, *replied = FALSE; - if (!strcmp (method_name, "RequestPassphrase")) { + if (nm_streq (method_name, "RequestPassphrase")) { const char *psk; if (!s_wireless_sec) @@ -1168,7 +1147,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; - } else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) { + } else if (nm_streq (method_name, "RequestPrivateKeyPassphrase")) { const char *password; if (!s_8021x) @@ -1188,7 +1167,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_name = NM_SETTING_802_1X_SETTING_NAME; *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; - } else if (!strcmp (method_name, "RequestUserNameAndPassword")) { + } else if (nm_streq (method_name, "RequestUserNameAndPassword")) { const char *identity, *password; if (!s_8021x) @@ -1212,7 +1191,7 @@ try_reply_agent_request (NMDeviceIwd *self, else *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; - } else if (!strcmp (method_name, "RequestUserPassword")) { + } else if (nm_streq (method_name, "RequestUserPassword")) { const char *password; if (!s_8021x) @@ -1270,7 +1249,7 @@ wifi_secrets_cb (NMActRequest *req, priv->wifi_secrets_id = NULL; - if (nm_utils_error_is_cancelled (error, FALSE)) { + if (nm_utils_error_is_cancelled (error)) { g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "NM secrets request cancelled"); @@ -1366,7 +1345,7 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if (!NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_NEED_AUTH)) @@ -1438,7 +1417,7 @@ act_failed_cb (GObject *source, GAsyncResult *res, gpointer user_data) gs_free_error GError *error = NULL; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); - if (!variant && nm_utils_error_is_cancelled (error, FALSE)) + if (!variant && nm_utils_error_is_cancelled (error)) return; /* Change state to FAILED unless already done by state_changed @@ -1467,7 +1446,7 @@ act_start_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if (!NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG)) @@ -1587,7 +1566,7 @@ act_set_mode_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Setting Device.Mode failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if ( !NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG) @@ -1647,7 +1626,7 @@ act_psk_cb (NMActRequest *req, NMDeviceIwdPrivate *priv; NMDevice *device; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -1772,29 +1751,25 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMActRequest *req; NMConnection *connection; NMSettingWireless *s_wireless; const char *mode; req = nm_device_get_act_request (device); - g_return_val_if_fail (req, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_act_request_get_applied_connection (req); - g_assert (connection); - s_wireless = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wireless, NM_ACT_STAGE_RETURN_FAILURE); mode = nm_setting_wireless_get_mode (s_wireless); + if (NM_IN_STRSET (mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { - GDBusProxy *network_proxy; + gs_unref_object GDBusProxy *network_proxy = NULL; NMWifiAP *ap = priv->current_ap; if (!ap) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; + goto out_fail; } /* 802.1x networks that are not IWD Known Networks will definitely @@ -1808,18 +1783,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_connection_get_id (connection)); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - goto out; + goto out_fail; } network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), - nm_wifi_ap_get_supplicant_path (ap), + nm_ref_string_get_str (nm_wifi_ap_get_supplicant_path (ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { _LOGE (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) could not get Network interface proxy for %s", - nm_wifi_ap_get_supplicant_path (ap)); + nm_ref_string_get_str (nm_wifi_ap_get_supplicant_path (ap))); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; + goto out_fail; } if (!priv->cancellable) @@ -1832,12 +1807,15 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NULL, G_DBUS_CALL_FLAGS_NONE, G_MAXINT, priv->cancellable, network_connect_cb, self); - g_object_unref (network_proxy); - } else if (NM_IN_STRSET (mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC)) { + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (NM_IN_STRSET (mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC)) { NMSettingWirelessSecurity *s_wireless_sec; s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - if (s_wireless_sec && !nm_setting_wireless_security_get_psk (s_wireless_sec)) { + if ( s_wireless_sec + && !nm_setting_wireless_security_get_psk (s_wireless_sec)) { /* PSK is missing from the settings, have to request it */ wifi_secrets_cancel (self); @@ -1852,16 +1830,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); } else act_set_mode (self); - } - /* We'll get stage3 started when the supplicant connects */ - ret = NM_ACT_STAGE_RETURN_POSTPONE; + return NM_ACT_STAGE_RETURN_POSTPONE; + } -out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - cleanup_association_attempt (self, FALSE); + _LOGW (LOGD_DEVICE | LOGD_WIFI, + "Activation: (wifi) iwd cannot handle mode %s", + mode); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return ret; +out_fail: + cleanup_association_attempt (self, FALSE); + return NM_ACT_STAGE_RETURN_FAILURE; } static guint32 @@ -1987,7 +1967,7 @@ device_state_changed (NMDevice *device, static gboolean get_enabled (NMDevice *device) { - return NM_DEVICE_IWD_GET_PRIVATE ((NMDeviceIwd *) device)->enabled; + return NM_DEVICE_IWD_GET_PRIVATE (device)->enabled; } static void @@ -2099,7 +2079,7 @@ get_property (GObject *object, guint prop_id, case PROP_LAST_SCAN: g_value_set_int64 (value, priv->last_scan > 0 - ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NS_PER_MSEC) + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NSEC_PER_MSEC) : (gint64) -1); break; default: @@ -2582,8 +2562,6 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) device_class->state_changed = device_state_changed; - klass->scanning_prohibited = scanning_prohibited; - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_IWD_MODE, "", "", NM_802_11_MODE_UNKNOWN, @@ -2628,12 +2606,4 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[SCANNING_PROHIBITED] = - g_signal_new (NM_DEVICE_IWD_SCANNING_PROHIBITED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceIwdClass, scanning_prohibited), - NULL, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); } diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h index 586e02f4..1f15d3f4 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -25,8 +25,6 @@ #define NM_DEVICE_IWD_SCANNING NM_DEVICE_WIFI_SCANNING #define NM_DEVICE_IWD_LAST_SCAN NM_DEVICE_WIFI_LAST_SCAN -#define NM_DEVICE_IWD_SCANNING_PROHIBITED NM_DEVICE_WIFI_SCANNING_PROHIBITED - typedef struct _NMDeviceIwd NMDeviceIwd; typedef struct _NMDeviceIwdClass NMDeviceIwdClass; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 516dc78b..770b53f6 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -57,7 +57,7 @@ struct _NMDeviceOlpcMeshClass { G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) -#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceOlpcMesh, NM_IS_DEVICE_OLPC_MESH) +#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceOlpcMesh, NM_IS_DEVICE_OLPC_MESH, NMDevice) /*****************************************************************************/ @@ -130,7 +130,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - gboolean scanning; /* disconnect companion device, if it is connected */ if (nm_device_get_act_request (NM_DEVICE (priv->companion))) { @@ -145,8 +144,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) } /* wait with continuing configuration until the companion device is done scanning */ - g_object_get (priv->companion, NM_DEVICE_WIFI_SCANNING, &scanning, NULL); - if (scanning) { + if (nm_device_wifi_get_scanning (NM_DEVICE_WIFI (priv->companion))) { priv->stage1_waiting = TRUE; return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -189,10 +187,10 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) gboolean success; s_mesh = nm_device_get_applied_setting (device, NM_TYPE_SETTING_OLPC_MESH); - g_return_val_if_fail (s_mesh, NM_ACT_STAGE_RETURN_FAILURE); ssid = nm_setting_olpc_mesh_get_ssid (s_mesh); + nm_device_take_down (NM_DEVICE (self), TRUE); success = nm_platform_mesh_set_ssid (nm_device_get_platform (device), nm_device_get_ifindex (device), @@ -237,6 +235,9 @@ companion_cleanup (NMDeviceOlpcMesh *self) NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); if (priv->companion) { + nm_device_wifi_scanning_prohibited_track (NM_DEVICE_WIFI (priv->companion), + self, + FALSE); g_signal_handlers_disconnect_by_data (priv->companion, self); g_clear_object (&priv->companion); } @@ -248,15 +249,16 @@ companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_d { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - gboolean scanning; + + nm_assert (NM_IS_DEVICE_WIFI (companion)); + nm_assert (priv->companion == (gpointer) companion); if (!priv->stage1_waiting) return; - g_object_get (companion, NM_DEVICE_WIFI_SCANNING, &scanning, NULL); - if (!scanning) { + if (!nm_device_wifi_get_scanning (NM_DEVICE_WIFI (companion))) { priv->stage1_waiting = FALSE; - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } } @@ -290,16 +292,6 @@ companion_state_changed_cb (NMDeviceWifi *companion, } static gboolean -companion_scan_prohibited_cb (NMDeviceWifi *companion, gboolean periodic, gpointer user_data) -{ - NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); - NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); - - /* Don't allow the companion to scan while configuring the mesh interface */ - return (state >= NM_DEVICE_STATE_PREPARE) && (state <= NM_DEVICE_STATE_IP_CONFIG); -} - -static gboolean companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); @@ -324,7 +316,7 @@ check_companion (NMDeviceOlpcMesh *self, NMDevice *other) if (!nm_utils_hwaddr_matches (my_addr, -1, their_addr, -1)) return FALSE; - g_assert (priv->companion == NULL); + nm_assert (priv->companion == NULL); priv->companion = g_object_ref (other); _LOGI (LOGD_OLPC, "found companion Wi-Fi device %s", @@ -336,9 +328,6 @@ check_companion (NMDeviceOlpcMesh *self, NMDevice *other) g_signal_connect (G_OBJECT (other), "notify::" NM_DEVICE_WIFI_SCANNING, G_CALLBACK (companion_notify_cb), self); - g_signal_connect (G_OBJECT (other), NM_DEVICE_WIFI_SCANNING_PROHIBITED, - G_CALLBACK (companion_scan_prohibited_cb), self); - g_signal_connect (G_OBJECT (other), NM_DEVICE_AUTOCONNECT_ALLOWED, G_CALLBACK (companion_autoconnect_allowed_cb), self); @@ -400,8 +389,24 @@ state_changed (NMDevice *device, NMDeviceState old_state, NMDeviceStateReason reason) { + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + if (new_state == NM_DEVICE_STATE_UNAVAILABLE) - find_companion (NM_DEVICE_OLPC_MESH (device)); + find_companion (self); + + if (priv->companion) { + gboolean temporarily_prohibited = FALSE; + + if ( new_state >= NM_DEVICE_STATE_PREPARE + && new_state <= NM_DEVICE_STATE_IP_CONFIG) { + /* Don't allow the companion to scan while configuring the mesh interface */ + temporarily_prohibited = TRUE; + } + nm_device_wifi_scanning_prohibited_track (NM_DEVICE_WIFI (priv->companion), + self, + temporarily_prohibited); + } } static guint32 diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c index 34ff70fa..497bc436 100644 --- a/src/devices/wifi/nm-device-wifi-p2p.c +++ b/src/devices/wifi/nm-device-wifi-p2p.c @@ -12,19 +12,20 @@ #include "supplicant/nm-supplicant-manager.h" #include "supplicant/nm-supplicant-interface.h" -#include "nm-manager.h" -#include "nm-utils.h" -#include "nm-wifi-p2p-peer.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" -#include "settings/nm-settings.h" -#include "nm-setting-wifi-p2p.h" #include "nm-act-request.h" +#include "nm-core-internal.h" +#include "nm-glib-aux/nm-ref-string.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" #include "nm-manager.h" -#include "nm-core-internal.h" +#include "nm-manager.h" +#include "nm-setting-wifi-p2p.h" +#include "nm-utils.h" +#include "nm-wifi-p2p-peer.h" +#include "platform/nm-platform.h" #include "platform/nmp-object.h" +#include "settings/nm-settings.h" #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWifiP2P); @@ -104,7 +105,7 @@ peer_list_dump (gpointer user_data) if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { NMWifiP2PPeer *peer; - gint32 now_s = nm_utils_get_monotonic_timestamp_s (); + gint32 now_s = nm_utils_get_monotonic_timestamp_sec (); _LOGD (LOGD_WIFI_SCAN, "P2P Peers: [now:%u]", now_s); c_list_for_each_entry (peer, &priv->peers_lst_head, peers_lst) @@ -227,11 +228,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return FALSE; supplicant_state = nm_supplicant_interface_get_state (priv->mgmt_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) - return FALSE; - - return TRUE; + return nm_supplicant_interface_state_is_operational (supplicant_state); } static gboolean @@ -432,7 +429,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) connection = nm_device_get_applied_connection (device); g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - nm_assert (NM_IS_SETTING_WIFI_P2P (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIFI_P2P))); /* The prepare stage ensures that the peer has been found */ @@ -452,7 +448,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* TODO: Fix "pbc" being hardcoded here! */ nm_supplicant_interface_p2p_connect (priv->mgmt_iface, nm_wifi_p2p_peer_get_supplicant_path (peer), - "pbc", NULL); + "pbc", + NULL); /* Set up a timeout on the connect attempt */ if (priv->sup_timeout_id == 0) { @@ -526,7 +523,7 @@ peer_add_remove (NMDeviceWifiP2P *self, if (peer) { /* A peer for the connection was found, cancel the timeout and go to configure state. */ nm_clear_g_source (&priv->find_peer_timeout_id); - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } } @@ -649,52 +646,49 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant management interface state: %s -> %s", nm_supplicant_interface_state_to_string (old_state), nm_supplicant_interface_state_to_string (new_state)); - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _LOGD (LOGD_WIFI, "supplicant ready"); + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { + supplicant_interfaces_release (self, TRUE); nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return; + } - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - _set_is_waiting_for_supplicant (self, FALSE); - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: - supplicant_interfaces_release (self, TRUE); + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + _LOGD (LOGD_WIFI, "supplicant ready"); nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - break; - default: - break; + _set_is_waiting_for_supplicant (self, FALSE); } } static void -supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, +supplicant_iface_peer_changed_cb (NMSupplicantInterface *iface, + NMSupplicantPeerInfo *peer_info, + gboolean is_present, NMDeviceWifiP2P *self) { - NMDeviceWifiP2PPrivate *priv; + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); NMWifiP2PPeer *found_peer; - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); + found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, peer_info->peer_path->str); - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + if (!is_present) { + if (!found_peer) + return; + + peer_add_remove (self, FALSE, found_peer, TRUE); + goto out; + } - found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); if (found_peer) { - if (!nm_wifi_p2p_peer_update_from_properties (found_peer, object_path, properties)) + if (!nm_wifi_p2p_peer_update_from_properties (found_peer, peer_info)) return; update_disconnect_on_connection_peer_missing (self); @@ -702,35 +696,11 @@ supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface, } else { gs_unref_object NMWifiP2PPeer *peer = NULL; - peer = nm_wifi_p2p_peer_new_from_properties (object_path, properties); - if (!peer) { - _LOGD (LOGD_WIFI, "invalid P2P peer properties received for %s", object_path); - return; - } - + peer = nm_wifi_p2p_peer_new_from_properties (peer_info); peer_add_remove (self, TRUE, peer, TRUE); } - schedule_peer_list_dump (self); -} - -static void -supplicant_iface_peer_removed_cb (NMSupplicantInterface *iface, - const char *object_path, - NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv; - NMWifiP2PPeer *peer; - - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); - - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); - peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); - if (!peer) - return; - - peer_add_remove (self, FALSE, peer, TRUE); +out: schedule_peer_list_dump (self); } @@ -742,7 +712,7 @@ check_group_iface_ready (NMDeviceWifiP2P *self) if (!priv->group_iface) return; - if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + if (!nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (priv->group_iface))) return; if (!nm_supplicant_interface_get_p2p_group_joined (priv->group_iface)) @@ -755,6 +725,24 @@ check_group_iface_ready (NMDeviceWifiP2P *self) } static void +supplicant_group_iface_is_ready (NMDeviceWifiP2P *self) +{ + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + + _LOGD (LOGD_WIFI, "P2P Group supplicant ready"); + + if (!nm_device_set_ip_iface (NM_DEVICE (self), nm_supplicant_interface_get_ifname (priv->group_iface))) { + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return; + } + + _set_is_waiting_for_supplicant (self, FALSE); + check_group_iface_ready (self); +} + +static void supplicant_group_iface_state_cb (NMSupplicantInterface *iface, int new_state_i, int old_state_i, @@ -762,44 +750,26 @@ supplicant_group_iface_state_cb (NMSupplicantInterface *iface, gpointer user_data) { NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _LOGI (LOGD_DEVICE | LOGD_WIFI, "P2P Group supplicant interface state: %s -> %s", nm_supplicant_interface_state_to_string (old_state), nm_supplicant_interface_state_to_string (new_state)); - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _LOGD (LOGD_WIFI, "P2P Group supplicant ready"); - - if (!nm_device_set_ip_iface (device, nm_supplicant_interface_get_ifname (priv->group_iface))) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - break; - } - - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - _set_is_waiting_for_supplicant (self, FALSE); - - check_group_iface_ready (self); - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { supplicant_group_interface_release (self); - nm_device_state_changed (device, + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - break; - default: - break; + return; + } + + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + supplicant_group_iface_is_ready (self); + return; } } @@ -833,8 +803,9 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, NMDeviceWifiP2P *self) { NMDeviceWifiP2PPrivate *priv; + NMSupplicantInterfaceState state; - g_return_if_fail (self != NULL); + g_return_if_fail (self); if (!nm_device_is_activating (NM_DEVICE (self))) { _LOGW (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant notified a group start but we are not trying to connect! Ignoring the event."); @@ -844,6 +815,7 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); supplicant_group_interface_release (self); + priv->group_iface = g_object_ref (group_iface); /* We need to wait for the interface to be ready and the group @@ -862,10 +834,13 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, G_CALLBACK (supplicant_group_iface_group_finished_cb), self); - if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + state = nm_supplicant_interface_get_state (priv->group_iface); + if (state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { _set_is_waiting_for_supplicant (self, TRUE); + return; + } - check_group_iface_ready (self); + supplicant_group_iface_is_ready (self); } static void @@ -935,9 +910,8 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_UNAVAILABLE: if ( !priv->mgmt_iface - || nm_supplicant_interface_get_state (priv->mgmt_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + || !nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (priv->mgmt_iface))) _set_is_waiting_for_supplicant (self, TRUE); - break; case NM_DEVICE_STATE_NEED_AUTH: /* Disconnect? */ @@ -1084,20 +1058,20 @@ nm_device_wifi_p2p_set_mgmt_iface (NMDeviceWifiP2P *self, goto done; _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.", - nm_supplicant_interface_get_object_path (iface)); + nm_ref_string_get_str (nm_supplicant_interface_get_object_path (iface))); priv->mgmt_iface = g_object_ref (iface); - g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_STATE, + g_signal_connect (priv->mgmt_iface, + NM_SUPPLICANT_INTERFACE_STATE, G_CALLBACK (supplicant_iface_state_cb), self); - g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_UPDATED, - G_CALLBACK (supplicant_iface_peer_updated_cb), - self); - g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_REMOVED, - G_CALLBACK (supplicant_iface_peer_removed_cb), + g_signal_connect (priv->mgmt_iface, + NM_SUPPLICANT_INTERFACE_PEER_CHANGED, + G_CALLBACK (supplicant_iface_peer_changed_cb), self); - g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_GROUP_STARTED, + g_signal_connect (priv->mgmt_iface, + NM_SUPPLICANT_INTERFACE_GROUP_STARTED, G_CALLBACK (supplicant_iface_group_started_cb), self); done: @@ -1106,8 +1080,7 @@ done: NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); _set_is_waiting_for_supplicant (self, !priv->mgmt_iface - || ( nm_supplicant_interface_get_state (priv->mgmt_iface) - < NM_SUPPLICANT_INTERFACE_STATE_READY)); + || !nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (priv->mgmt_iface))); } void diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 98f9df25..266a8425 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -11,6 +11,8 @@ #include <netinet/in.h> #include <unistd.h> +#include "nm-glib-aux/nm-ref-string.h" +#include "nm-glib-aux/nm-c-list.h" #include "nm-device-wifi-p2p.h" #include "nm-wifi-ap.h" #include "nm-libnm-core-intern/nm-common-macros.h" @@ -42,10 +44,9 @@ #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWifi); -/* All of these are in seconds */ -#define SCAN_INTERVAL_MIN 3 -#define SCAN_INTERVAL_STEP 20 -#define SCAN_INTERVAL_MAX 120 +#define SCAN_INTERVAL_SEC_MIN 3 +#define SCAN_INTERVAL_SEC_STEP 20 +#define SCAN_INTERVAL_SEC_MAX 120 #define SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN 5 @@ -62,7 +63,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi, ); enum { - SCANNING_PROHIBITED, P2P_DEVICE_CREATED, LAST_SIGNAL @@ -71,9 +71,10 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - gint8 invalid_strength_counter; - CList aps_lst_head; + GHashTable *aps_idx_by_supplicant_path; + + CList scanning_prohibited_lst_head; NMWifiAP * current_ap; guint32 rate; @@ -83,13 +84,15 @@ typedef struct { bool is_scanning:1; bool hidden_probe_scan_warn:1; - gint64 last_scan; /* milliseconds */ + gint64 last_scan_msec; + gint32 scheduled_scan_time; /* seconds */ - guint8 scan_interval; /* seconds */ + guint8 scan_interval_sec; guint pending_scan_id; guint ap_dump_id; NMSupplicantManager *sup_mgr; + NMSupplMgrCreateIfaceHandle *sup_create_handle; NMSupplicantInterface *sup_iface; guint sup_timeout_id; /* supplicant association timeout */ @@ -97,7 +100,7 @@ typedef struct { NMActRequestGetSecretsCallId *wifi_secrets_id; - guint periodic_source_id; + guint periodic_update_id; guint link_timeout_id; guint32 failed_iface_count; guint reacquire_iface_id; @@ -122,53 +125,46 @@ struct _NMDeviceWifi struct _NMDeviceWifiClass { NMDeviceClass parent; - - /* Signals */ - gboolean (*scanning_prohibited) (NMDeviceWifi *device, gboolean periodic); }; /*****************************************************************************/ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) -#define NM_DEVICE_WIFI_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceWifi, NM_IS_DEVICE_WIFI) +#define NM_DEVICE_WIFI_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceWifi, NM_IS_DEVICE_WIFI, NMDevice) /*****************************************************************************/ static gboolean check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic); +static void supplicant_iface_state_down (NMDeviceWifi *self); + static void schedule_scan (NMDeviceWifi *self, gboolean backoff); static void cleanup_association_attempt (NMDeviceWifi * self, gboolean disconnect); +static void supplicant_iface_state (NMDeviceWifi *self, + NMSupplicantInterfaceState new_state, + NMSupplicantInterfaceState old_state, + int disconnect_reason, + gboolean is_real_signal); + static void supplicant_iface_state_cb (NMSupplicantInterface *iface, int new_state_i, int old_state_i, int disconnect_reason, gpointer user_data); -static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi *self); - -static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, - const char *object_path, +static void supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface, + NMSupplicantBssInfo *bss_info, + gboolean is_present, NMDeviceWifi *self); -static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface, - gboolean success, - NMDeviceWifi * self); - static void supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface, GVariant *credentials, NMDeviceWifi *self); -static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface, - GParamSpec * pspec, - NMDeviceWifi * self); - static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); @@ -177,6 +173,10 @@ static void supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); +static void _requested_scan_set (NMDeviceWifi *self, gboolean value); + +static void periodic_update (NMDeviceWifi *self); + static void request_wireless_scan (NMDeviceWifi *self, gboolean periodic, gboolean force_if_scanning, @@ -193,19 +193,66 @@ static void recheck_p2p_availability (NMDeviceWifi *self); /*****************************************************************************/ +void +nm_device_wifi_scanning_prohibited_track (NMDeviceWifi *self, + gpointer tag, + gboolean temporarily_prohibited) +{ + NMDeviceWifiPrivate *priv; + NMCListElem *elem; + + g_return_if_fail (NM_IS_DEVICE_WIFI (self)); + nm_assert (tag); + + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + /* We track these with a simple CList. This would be not efficient, if + * there would be many users that need to be tracked at the same time (there + * aren't). In fact, most of the time there is no NMDeviceOlpcMesh and + * nobody tracks itself here. Optimize for that and simplicity. */ + + elem = nm_c_list_elem_find_first (&priv->scanning_prohibited_lst_head, + iter, + iter == tag); + + if (!temporarily_prohibited) { + if (!elem) + return; + + nm_c_list_elem_free (elem); + return; + } + + if (elem) + return; + + c_list_link_tail (&priv->scanning_prohibited_lst_head, + &nm_c_list_elem_new_stale (tag)->lst); +} + +/*****************************************************************************/ + static void _ap_dump (NMDeviceWifi *self, NMLogLevel log_level, const NMWifiAP *ap, const char *prefix, - gint32 now_s) + gint64 now_msec) { char buf[1024]; buf[0] = '\0'; _NMLOG (log_level, LOGD_WIFI_SCAN, "wifi-ap: %-7s %s", prefix, - nm_wifi_ap_to_string (ap, buf, sizeof (buf), now_s)); + nm_wifi_ap_to_string (ap, buf, sizeof (buf), now_msec)); +} + +gboolean +nm_device_wifi_get_scanning (NMDeviceWifi *self) +{ + g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), FALSE); + + return NM_DEVICE_WIFI_GET_PRIVATE (self)->is_scanning; } static void @@ -213,6 +260,7 @@ _notify_scanning (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); gboolean scanning; + gboolean last_scan_changed = FALSE; scanning = priv->sup_iface && nm_supplicant_interface_get_scanning (priv->sup_iface); @@ -220,9 +268,42 @@ _notify_scanning (NMDeviceWifi *self) if (scanning == priv->is_scanning) return; - _LOGD (LOGD_WIFI, "wifi-scan: scanning-state: %s", scanning ? "scanning" : "idle"); priv->is_scanning = scanning; - _notify (self, PROP_SCANNING); + + if ( !scanning + || priv->last_scan_msec == 0) { + last_scan_changed = TRUE; + priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec (); + } + + _LOGD (LOGD_WIFI, + "wifi-scan: scanning-state: %s%s", + scanning ? "scanning" : "idle", + last_scan_changed ? " (notify last-scan)" : ""); + + schedule_scan (self, TRUE); + + nm_gobject_notify_together (self, + PROP_SCANNING, + last_scan_changed + ? PROP_LAST_SCAN + : PROP_0); + + if (!priv->is_scanning) { + _requested_scan_set (self, FALSE); + if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) { + /* Run a quick update of current AP when coming out of a scan */ + periodic_update (self); + } + } +} + +static void +supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self) +{ + _notify_scanning (self); } static gboolean @@ -237,40 +318,40 @@ unmanaged_on_quit (NMDevice *self) return TRUE; } -static gboolean -supplicant_interface_acquire (NMDeviceWifi *self) +static void +supplicant_interface_acquire_cb (NMSupplicantManager *supplicant_manager, + NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { + NMDeviceWifi *self = user_data; NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (!priv->sup_iface, TRUE); + if (nm_utils_error_is_cancelled (error)) + return; - priv->sup_iface = nm_supplicant_manager_create_interface (priv->sup_mgr, - nm_device_get_iface (NM_DEVICE (self)), - NM_SUPPLICANT_DRIVER_WIRELESS); - if (!priv->sup_iface) { - _LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface"); - return FALSE; + nm_assert (priv->sup_create_handle == handle); + + priv->sup_create_handle = NULL; + + if (error) { + _LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface: %s", + error->message); + supplicant_iface_state_down (self); + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); + return; } - if (nm_supplicant_interface_get_state (priv->sup_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE); + priv->sup_iface = g_object_ref (iface); g_signal_connect (priv->sup_iface, NM_SUPPLICANT_INTERFACE_STATE, G_CALLBACK (supplicant_iface_state_cb), self); g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_BSS_UPDATED, - G_CALLBACK (supplicant_iface_bss_updated_cb), - self); - g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_BSS_REMOVED, - G_CALLBACK (supplicant_iface_bss_removed_cb), - self); - g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_SCAN_DONE, - G_CALLBACK (supplicant_iface_scan_done_cb), + NM_SUPPLICANT_INTERFACE_BSS_CHANGED, + G_CALLBACK (supplicant_iface_bss_changed_cb), self); g_signal_connect (priv->sup_iface, NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS, @@ -291,7 +372,30 @@ supplicant_interface_acquire (NMDeviceWifi *self) _notify_scanning (self); - return TRUE; + if (nm_supplicant_interface_get_state (priv->sup_iface) != NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + /* fake an initial state change. */ + supplicant_iface_state (user_data, + NM_SUPPLICANT_INTERFACE_STATE_STARTING, + nm_supplicant_interface_get_state (priv->sup_iface), + 0, + FALSE); + } +} + +static void +supplicant_interface_acquire (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + nm_assert (!priv->sup_iface); + nm_assert (!priv->sup_create_handle); + + priv->sup_create_handle = nm_supplicant_manager_create_interface (priv->sup_mgr, + nm_device_get_ifindex (NM_DEVICE (self)), + NM_SUPPLICANT_DRIVER_WIRELESS, + supplicant_interface_acquire_cb, + self); + nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); } static void @@ -310,27 +414,26 @@ _requested_scan_set (NMDeviceWifi *self, gboolean value) nm_device_add_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); else { nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - nm_device_remove_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WIFI_SCAN, TRUE); } } static void supplicant_interface_release (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv; - - g_return_if_fail (self != NULL); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + if (nm_clear_pointer (&priv->sup_create_handle, nm_supplicant_manager_create_interface_cancel)) + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); _requested_scan_set (self, FALSE); nm_clear_g_source (&priv->pending_scan_id); /* Reset the scan interval to be pretty frequent when disconnected */ - priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP; + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN + SCAN_INTERVAL_SEC_STEP; _LOGD (LOGD_WIFI, "wifi-scan: reset interval to %u seconds", - (unsigned) priv->scan_interval); + (unsigned) priv->scan_interval_sec); nm_clear_g_source (&priv->ap_dump_id); @@ -410,44 +513,48 @@ set_current_ap (NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available static void periodic_update (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); + NMDeviceWifiPrivate *priv; + int ifindex; guint32 new_rate; - int percent; - NMDeviceState state; - NMSupplicantInterfaceState supplicant_state; - /* BSSID and signal strength have meaningful values only if the device - * is activated and not scanning. - */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state != NM_DEVICE_STATE_ACTIVATED) + if (nm_device_get_state (NM_DEVICE (self)) != NM_DEVICE_STATE_ACTIVATED) { + /* BSSID and signal strength have meaningful values only if the device + * is activated and not scanning. + */ return; + } - /* Only update current AP if we're actually talking to something, otherwise - * assume the old one (if any) is still valid until we're told otherwise or - * the connection fails. - */ - supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED - || nm_supplicant_interface_get_scanning (priv->sup_iface)) + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + if ( !nm_supplicant_interface_state_is_associated (nm_supplicant_interface_get_state (priv->sup_iface)) + || nm_supplicant_interface_get_scanning (priv->sup_iface)) { + /* Only update current AP if we're actually talking to something, otherwise + * assume the old one (if any) is still valid until we're told otherwise or + * the connection fails. + */ return; + } - /* In AP mode we currently have nothing to do. */ - if (priv->mode == NM_802_11_MODE_AP) + if (priv->mode == NM_802_11_MODE_AP) { + /* In AP mode we currently have nothing to do. */ return; + } + + ifindex = nm_device_get_ifindex (NM_DEVICE (self)); + if (ifindex <= 0) + g_return_if_reached (); if (priv->current_ap) { - /* Smooth out the strength to work around crappy drivers */ + int percent; + percent = nm_platform_wifi_get_quality (nm_device_get_platform (NM_DEVICE (self)), ifindex); - if (percent >= 0 || ++priv->invalid_strength_counter > 3) { + if ( percent >= 0 + && percent <= 100) { if (nm_wifi_ap_set_strength (priv->current_ap, (gint8) percent)) { #if NM_MORE_LOGGING _ap_dump (self, LOGL_TRACE, priv->current_ap, "updated", 0); #endif } - priv->invalid_strength_counter = 0; } } @@ -461,7 +568,7 @@ periodic_update (NMDeviceWifi *self) static gboolean periodic_update_cb (gpointer user_data) { - periodic_update (NM_DEVICE_WIFI (user_data)); + periodic_update (user_data); return TRUE; } @@ -477,12 +584,16 @@ ap_add_remove (NMDeviceWifi *self, g_object_ref (ap); ap->wifi_device = NM_DEVICE (self); c_list_link_tail (&priv->aps_lst_head, &ap->aps_lst); + if (!g_hash_table_insert (priv->aps_idx_by_supplicant_path, nm_wifi_ap_get_supplicant_path (ap), ap)) + nm_assert_not_reached (); nm_dbus_object_export (NM_DBUS_OBJECT (ap)); _ap_dump (self, LOGL_DEBUG, ap, "added", 0); nm_device_wifi_emit_signal_access_point (NM_DEVICE (self), ap, TRUE); } else { ap->wifi_device = NULL; c_list_unlink (&ap->aps_lst); + if (!g_hash_table_remove (priv->aps_idx_by_supplicant_path, nm_wifi_ap_get_supplicant_path (ap))) + nm_assert_not_reached (); _ap_dump (self, LOGL_DEBUG, ap, "removed", 0); } @@ -593,7 +704,7 @@ deactivate (NMDevice *device) int ifindex = nm_device_get_ifindex (device); NM80211Mode old_mode = priv->mode; - nm_clear_g_source (&priv->periodic_source_id); + nm_clear_g_source (&priv->periodic_update_id); cleanup_association_attempt (self, TRUE); @@ -694,7 +805,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError } if (priv->sup_iface) { - if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + if (nm_supplicant_interface_get_capability (priv->sup_iface, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_FALSE) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "wpa_supplicant does not support Access Point mode"); return FALSE; @@ -708,7 +819,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError } if (priv->sup_iface) { - if (nm_supplicant_interface_get_mesh_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + if (nm_supplicant_interface_get_capability (priv->sup_iface, NM_SUPPL_CAP_TYPE_MESH) == NM_TERNARY_FALSE) { nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "wpa_supplicant does not support Mesh mode"); return FALSE; @@ -936,7 +1047,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return FALSE; supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY + if ( supplicant_state <= NM_SUPPLICANT_INTERFACE_STATE_STARTING || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) return FALSE; @@ -1047,7 +1158,7 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) return; } - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); if (now >= priv->hw_addr_scan_expire) { gs_free char *generate_mac_address_mask = NULL; @@ -1074,16 +1185,17 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) static GPtrArray * ssids_options_to_ptrarray (GVariant *value, GError **error) { - GPtrArray *ssids = NULL; - const guint8 *bytes; - gsize len; - int num_ssids, i; + gs_unref_ptrarray GPtrArray *ssids = NULL; + gsize num_ssids; + gsize i; + + nm_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("aay"))); num_ssids = g_variant_n_children (value); if (num_ssids > 32) { g_set_error_literal (error, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, + NM_DEVICE_ERROR_INVALID_ARGUMENT, "too many SSIDs requested to scan"); return NULL; } @@ -1092,22 +1204,30 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_bytes_unref); for (i = 0; i < num_ssids; i++) { gs_unref_variant GVariant *v = NULL; + gsize len; + const guint8 *bytes; v = g_variant_get_child_value (value, i); bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); if (len > 32) { g_set_error (error, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "SSID at index %d more than 32 bytes", i); - g_ptr_array_unref (ssids); + NM_DEVICE_ERROR_INVALID_ARGUMENT, + "SSID at index %d more than 32 bytes", (int) i); return NULL; } g_ptr_array_add (ssids, g_bytes_new (bytes, len)); } } - return ssids; + + return g_steal_pointer (&ssids); +} + +GPtrArray * +nmtst_ssids_options_to_ptrarray (GVariant *value, GError **error) +{ + return ssids_options_to_ptrarray (value, error); } static void @@ -1118,8 +1238,7 @@ dbus_request_scan_cb (NMDevice *device, gpointer user_data) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - gs_unref_variant GVariant *scan_options = user_data; - gs_unref_ptrarray GPtrArray *ssids = NULL; + gs_unref_ptrarray GPtrArray *ssids = user_data; if (error) { g_dbus_method_invocation_return_gerror (context, error); @@ -1134,41 +1253,42 @@ dbus_request_scan_cb (NMDevice *device, return; } - if (scan_options) { - gs_unref_variant GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL); + request_wireless_scan (self, FALSE, FALSE, ssids); + g_dbus_method_invocation_return_value (context, NULL); +} + +void +_nm_device_wifi_request_scan (NMDeviceWifi *self, + GVariant *options, + GDBusMethodInvocation *invocation) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + gint64 last_scan; + gs_unref_ptrarray GPtrArray *ssids = NULL; + + if (options) { + gs_unref_variant GVariant *val = g_variant_lookup_value (options, "ssids", NULL); if (val) { gs_free_error GError *ssid_error = NULL; if (!g_variant_is_of_type (val, G_VARIANT_TYPE ("aay"))) { - g_dbus_method_invocation_return_error_literal (context, + g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, + NM_DEVICE_ERROR_INVALID_ARGUMENT, "Invalid 'ssid' scan option"); return; } ssids = ssids_options_to_ptrarray (val, &ssid_error); if (ssid_error) { - g_dbus_method_invocation_return_gerror (context, ssid_error); + g_dbus_method_invocation_return_gerror (invocation, ssid_error); return; } } } - request_wireless_scan (self, FALSE, FALSE, ssids); - g_dbus_method_invocation_return_value (context, NULL); -} - -void -_nm_device_wifi_request_scan (NMDeviceWifi *self, - GVariant *options, - GDBusMethodInvocation *invocation) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - gint64 last_scan; - if ( !priv->enabled || !priv->sup_iface || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED @@ -1189,7 +1309,13 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, } last_scan = nm_supplicant_interface_get_last_scan (priv->sup_iface); - if (last_scan && (nm_utils_get_monotonic_timestamp_ms () - last_scan) < 10 * NM_UTILS_MSEC_PER_SECOND) { + if ( last_scan > 0 + && nm_utils_get_monotonic_timestamp_msec () < last_scan + (10 * NM_UTILS_MSEC_PER_SEC)) { + /* FIXME: we really should not outright reject a scan request in this case. We should + * ensure to start a scan request soon, possibly with rate limiting. And there is no + * need to tell the caller that we aren't going to scan... + * + * Same above, if we are currently scanning... */ g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, @@ -1204,16 +1330,19 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, NM_AUTH_PERMISSION_WIFI_SCAN, TRUE, dbus_request_scan_cb, - options ? g_variant_ref (options) : NULL); + g_steal_pointer (&ssids)); } static gboolean -scanning_prohibited (NMDeviceWifi *self, gboolean periodic) +check_scanning_prohibited (NMDeviceWifi *self, + gboolean periodic) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMSupplicantInterfaceState supplicant_state; - g_return_val_if_fail (priv->sup_iface != NULL, TRUE); + nm_assert (NM_IS_SUPPLICANT_INTERFACE (priv->sup_iface)); + + if (!c_list_is_empty (&priv->scanning_prohibited_lst_head)) + return TRUE; /* Don't scan when a an AP or Ad-Hoc connection is active as it will * disrupt connected clients or peers. @@ -1250,11 +1379,11 @@ scanning_prohibited (NMDeviceWifi *self, gboolean periodic) } /* Prohibit scans if the supplicant is busy */ - supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE + if ( NM_IN_SET (nm_supplicant_interface_get_state (priv->sup_iface), + NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, + NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, + NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, + NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE) || nm_supplicant_interface_get_scanning (priv->sup_iface)) return TRUE; @@ -1263,15 +1392,6 @@ scanning_prohibited (NMDeviceWifi *self, gboolean periodic) } static gboolean -check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic) -{ - gboolean prohibited = FALSE; - - g_signal_emit (self, signals[SCANNING_PROHIBITED], 0, periodic, &prohibited); - return prohibited; -} - -static gboolean hidden_filter_func (NMSettings *settings, NMSettingsConnection *set_con, gpointer user_data) @@ -1420,16 +1540,17 @@ static void schedule_scan (NMDeviceWifi *self, gboolean backoff) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); - /* Cancel the pending scan if it would happen later than (now + the scan_interval) */ + /* Cancel the pending scan if it would happen later than (now + the scan_interval_sec) */ if (priv->pending_scan_id) { - if (now + priv->scan_interval < priv->scheduled_scan_time) + if (now + priv->scan_interval_sec < priv->scheduled_scan_time) nm_clear_g_source (&priv->pending_scan_id); } if (!priv->pending_scan_id) { - guint factor = 2, next_scan = priv->scan_interval; + guint factor = 2; + guint next_scan = priv->scan_interval_sec; if ( nm_device_is_activating (NM_DEVICE (self)) || (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED)) @@ -1439,41 +1560,25 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff) request_wireless_scan_periodic, self); - priv->scheduled_scan_time = now + priv->scan_interval; - if (backoff && (priv->scan_interval < (SCAN_INTERVAL_MAX / factor))) { - priv->scan_interval += (SCAN_INTERVAL_STEP / factor); + priv->scheduled_scan_time = now + priv->scan_interval_sec; + if (backoff && (priv->scan_interval_sec < (SCAN_INTERVAL_SEC_MAX / factor))) { + priv->scan_interval_sec += (SCAN_INTERVAL_SEC_STEP / factor); /* Ensure the scan interval will never be less than 20s... */ - priv->scan_interval = MAX(priv->scan_interval, SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP); + priv->scan_interval_sec = MAX(priv->scan_interval_sec, SCAN_INTERVAL_SEC_MIN + SCAN_INTERVAL_SEC_STEP); /* ... or more than 120s */ - priv->scan_interval = MIN(priv->scan_interval, SCAN_INTERVAL_MAX); - } else if (!backoff && (priv->scan_interval == 0)) { + priv->scan_interval_sec = MIN(priv->scan_interval_sec, SCAN_INTERVAL_SEC_MAX); + } else if (!backoff && (priv->scan_interval_sec == 0)) { /* Invalid combination; would cause continual rescheduling of * the scan and hog CPU. Reset to something minimally sane. */ - priv->scan_interval = 5; + priv->scan_interval_sec = 5; } _LOGD (LOGD_WIFI, "wifi-scan: scheduled in %d seconds (interval now %d seconds)", - next_scan, priv->scan_interval); + next_scan, priv->scan_interval_sec); } } -static void -supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, - gboolean success, - NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - _LOGD (LOGD_WIFI, "wifi-scan: scan-done callback: %s", success ? "successful" : "failed"); - - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); - _notify (self, PROP_LAST_SCAN); - schedule_scan (self, success); - - _requested_scan_set (self, FALSE); -} - /**************************************************************************** * WPA Supplicant control stuff * @@ -1489,14 +1594,21 @@ ap_list_dump (gpointer user_data) if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { NMWifiAP *ap; - gint32 now_s = nm_utils_get_monotonic_timestamp_s (); - - _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%" G_GINT64_FORMAT " next:%u]", - now_s, - priv->last_scan / NM_UTILS_MSEC_PER_SECOND, + gint64 now_msec = nm_utils_get_monotonic_timestamp_msec (); + char str_buf[100]; + + _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u.%03u, last:%s, next:%u]", + (guint) (now_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec % NM_UTILS_MSEC_PER_SEC), + priv->last_scan_msec > 0 + ? nm_sprintf_buf (str_buf, + "%u.%03u", + (guint) (priv->last_scan_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (priv->last_scan_msec % NM_UTILS_MSEC_PER_SEC)) + : "-1", priv->scheduled_scan_time); c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) - _ap_dump (self, LOGL_DEBUG, ap, "dump", now_s); + _ap_dump (self, LOGL_DEBUG, ap, "dump", now_msec); } return G_SOURCE_REMOVE; } @@ -1543,40 +1655,43 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, } static void -supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, +supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface, + NMSupplicantBssInfo *bss_info, + gboolean is_present, NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMDeviceState state; - NMWifiAP *found_ap = NULL; + NMWifiAP *found_ap; GBytes *ssid; - g_return_if_fail (self != NULL); - g_return_if_fail (properties != NULL); - g_return_if_fail (iface != NULL); + found_ap = g_hash_table_lookup (priv->aps_idx_by_supplicant_path, bss_info->bss_path); - /* Ignore new APs when unavailable, unmanaged, or in AP mode */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - return; - if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) + if (!is_present) { + if (!found_ap) + return; + if (found_ap == priv->current_ap) { + /* The current AP cannot be removed (to prevent NM indicating that + * it is connected, but to nothing), but it must be removed later + * when the current AP is changed or cleared. Set 'fake' to + * indicate that this AP is now unknown to the supplicant. + */ + if (nm_wifi_ap_set_fake (found_ap, TRUE)) + _ap_dump (self, LOGL_DEBUG, found_ap, "updated", 0); + } else { + ap_add_remove (self, FALSE, found_ap, TRUE); + schedule_ap_list_dump (self); + } return; + } - found_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path); if (found_ap) { - if (!nm_wifi_ap_update_from_properties (found_ap, object_path, properties)) + if (!nm_wifi_ap_update_from_properties (found_ap, bss_info)) return; _ap_dump (self, LOGL_DEBUG, found_ap, "updated", 0); } else { gs_unref_object NMWifiAP *ap = NULL; - ap = nm_wifi_ap_new_from_properties (object_path, properties); - if (!ap) { - _LOGD (LOGD_WIFI, "invalid AP properties received for %s", object_path); - return; - } + ap = nm_wifi_ap_new_from_properties (bss_info); /* Let the manager try to fill in the SSID from seen-bssids lists */ ssid = nm_wifi_ap_get_ssid (ap); @@ -1606,43 +1721,13 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, /* Update the current AP if the supplicant notified a current BSS change * before it sent the current BSS's scan result. */ - if (g_strcmp0 (nm_supplicant_interface_get_current_bss (iface), object_path) == 0) + if (nm_supplicant_interface_get_current_bss (iface) == bss_info->bss_path) supplicant_iface_notify_current_bss (priv->sup_iface, NULL, self); schedule_ap_list_dump (self); } static void -supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, - const char *object_path, - NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv; - NMWifiAP *ap; - - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); - - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path); - if (!ap) - return; - - if (ap == priv->current_ap) { - /* The current AP cannot be removed (to prevent NM indicating that - * it is connected, but to nothing), but it must be removed later - * when the current AP is changed or cleared. Set 'fake' to - * indicate that this AP is now unknown to the supplicant. - */ - if (nm_wifi_ap_set_fake (ap, TRUE)) - _ap_dump (self, LOGL_DEBUG, ap, "updated", 0); - } else { - ap_add_remove (self, FALSE, ap, TRUE); - schedule_ap_list_dump (self); - } -} - -static void cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -1725,7 +1810,7 @@ wifi_secrets_cb (NMActRequest *req, return; } - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -1792,7 +1877,7 @@ supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface, } wifi_secrets_cancel (self); - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } static gboolean @@ -2020,50 +2105,71 @@ reacquire_interface_cb (gpointer user_data) } static void -supplicant_iface_state_cb (NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) +supplicant_iface_state_down (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + cleanup_association_attempt (self, FALSE); + + /* If the device is already in UNAVAILABLE state then the state change + * is a NOP and the interface won't be re-acquired in the device state + * change handler. So ensure we have a new one here so that we're + * ready if the supplicant comes back. + */ + supplicant_interface_release (self); + if (priv->failed_iface_count < 5) + priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self); + else + _LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up"); +} + +static void +supplicant_iface_state (NMDeviceWifi *self, + NMSupplicantInterfaceState new_state, + NMSupplicantInterfaceState old_state, + int disconnect_reason, + gboolean is_real_signal) { - NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); NMDeviceState devstate; gboolean scanning; - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - if (new_state == old_state) - return; _LOGI (LOGD_DEVICE | LOGD_WIFI, - "supplicant interface state: %s -> %s", + "supplicant interface state: %s -> %s%s", nm_supplicant_interface_state_to_string (old_state), - nm_supplicant_interface_state_to_string (new_state)); + nm_supplicant_interface_state_to_string (new_state), + is_real_signal ? "" : " (simulated signal)"); + + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { + supplicant_iface_state_down (self); + goto out; + } devstate = nm_device_get_state (device); - scanning = nm_supplicant_interface_get_scanning (iface); + scanning = nm_supplicant_interface_get_scanning (priv->sup_iface); + + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + _LOGD (LOGD_WIFI, "supplicant ready"); + nm_device_queue_recheck_available (NM_DEVICE (device), + NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN; + } /* In these states we know the supplicant is actually talking to something */ if ( new_state >= NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING && new_state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) priv->ssid_found = TRUE; - if ( old_state < NM_SUPPLICANT_INTERFACE_STATE_READY - && new_state >= NM_SUPPLICANT_INTERFACE_STATE_READY) + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) recheck_p2p_availability (self); switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _LOGD (LOGD_WIFI, "supplicant ready"); - nm_device_queue_recheck_available (NM_DEVICE (device), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - priv->scan_interval = SCAN_INTERVAL_MIN; - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: nm_clear_g_source (&priv->sup_timeout_id); nm_clear_g_source (&priv->link_timeout_id); @@ -2118,26 +2224,6 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, } } break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: - nm_device_queue_recheck_available (NM_DEVICE (device), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - cleanup_association_attempt (self, FALSE); - - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - - /* If the device is already in UNAVAILABLE state then the state change - * is a NOP and the interface won't be re-acquired in the device state - * change handler. So ensure we have a new one here so that we're - * ready if the supplicant comes back. - */ - supplicant_interface_release (self); - if (priv->failed_iface_count < 5) - priv->reacquire_iface_id = g_timeout_add_seconds (10, reacquire_interface_cb, self); - else - _LOGI (LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up"); - break; case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE: /* we would clear _requested_scan_set() and trigger a new scan. * However, we don't want to cancel the current pending action, so force @@ -2148,10 +2234,25 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, break; } - /* Signal scanning state changes */ - if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING - || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) - _notify_scanning (self); +out: + _notify_scanning (self); + + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) + nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); +} + +static void +supplicant_iface_state_cb (NMSupplicantInterface *iface, + int new_state_i, + int old_state_i, + int disconnect_reason, + gpointer user_data) +{ + supplicant_iface_state (user_data, + new_state_i, + old_state_i, + disconnect_reason, + TRUE); } static void @@ -2162,7 +2263,7 @@ supplicant_iface_assoc_cb (NMSupplicantInterface *iface, NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDevice *device = NM_DEVICE (self); - if ( error && !nm_utils_error_is_cancelled (error, TRUE) + if ( error && !nm_utils_error_is_cancelled_or_disposing (error) && nm_device_is_activating (device)) { cleanup_association_attempt (self, TRUE); nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); @@ -2170,30 +2271,17 @@ supplicant_iface_assoc_cb (NMSupplicantInterface *iface, } static void -supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, - GParamSpec *pspec, - NMDeviceWifi *self) -{ - _notify_scanning (self); - - /* Run a quick update of current AP when coming out of a scan */ - if ( !NM_DEVICE_WIFI_GET_PRIVATE (self)->is_scanning - && nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self); -} - -static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - const char *current_bss; + NMRefString *current_bss; NMWifiAP *new_ap = NULL; current_bss = nm_supplicant_interface_get_current_bss (iface); if (current_bss) - new_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, current_bss); + new_ap = g_hash_table_lookup (priv->aps_idx_by_supplicant_path, current_bss); if (new_ap != priv->current_ap) { const char *new_bssid = NULL; @@ -2284,11 +2372,8 @@ supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self) { - /* Do not update when the interface is still initializing. */ - if (nm_supplicant_interface_get_state (iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) - return; - - recheck_p2p_availability (self); + if (nm_supplicant_interface_get_state (iface) > NM_SUPPLICANT_INTERFACE_STATE_STARTING) + recheck_p2p_availability (self); } static gboolean @@ -2472,15 +2557,11 @@ build_supplicant_config (NMDeviceWifi *self, s_wireless = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wireless != NULL, NULL); - config = nm_supplicant_config_new ( - nm_supplicant_interface_get_pmf_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_fils_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_ft_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_sha384_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES); + config = nm_supplicant_config_new (nm_supplicant_interface_get_capabilities (priv->sup_iface)); /* Warn if AP mode may not be supported */ - if ( g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0 - && nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_UNKNOWN) { + if ( nm_streq0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) + && nm_supplicant_interface_get_capability (priv->sup_iface, NM_SUPPL_CAP_TYPE_AP) != NM_TERNARY_TRUE) { _LOGW (LOGD_WIFI, "Supplicant may not support AP mode; connection may time out."); } @@ -2753,8 +2834,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMSupplicantConfig *config = NULL; + gs_unref_object NMSupplicantConfig *config = NULL; NM80211Mode ap_mode; NMActRequest *req; NMWifiAP *ap; @@ -2774,15 +2854,14 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) ap = priv->current_ap; if (!ap) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; + goto out_fail; } + ap_mode = nm_wifi_ap_get_mode (ap); connection = nm_act_request_get_applied_connection (req); - g_assert (connection); - s_wireless = nm_connection_get_setting_wireless (connection); - g_assert (s_wireless); + nm_assert (s_wireless); /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); @@ -2791,13 +2870,12 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) "Activation: (wifi) access point '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - if (handle_auth_or_fail (self, req, FALSE)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else { + if (!handle_auth_or_fail (self, req, FALSE)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; + goto out_fail; } - goto out; + + return NM_ACT_STAGE_RETURN_POSTPONE; } if (!wake_on_wlan_enable (self)) @@ -2830,17 +2908,19 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* Build up the supplicant configuration */ config = build_supplicant_config (self, connection, nm_wifi_ap_get_freq (ap), &error); - if (config == NULL) { + if (!config) { _LOGE (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) couldn't build wireless configuration: %s", error->message); g_clear_error (&error); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - goto out; + goto out_fail; } - nm_supplicant_interface_assoc (priv->sup_iface, config, - supplicant_iface_assoc_cb, self); + nm_supplicant_interface_assoc (priv->sup_iface, + config, + supplicant_iface_assoc_cb, + self); /* Set up a timeout on the association attempt */ timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); @@ -2848,25 +2928,16 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) supplicant_connection_timeout_cb, self); - if (!priv->periodic_source_id) - priv->periodic_source_id = g_timeout_add_seconds (6, periodic_update_cb, self); + if (!priv->periodic_update_id) + priv->periodic_update_id = g_timeout_add_seconds (6, periodic_update_cb, self); /* We'll get stage3 started when the supplicant connects */ - ret = NM_ACT_STAGE_RETURN_POSTPONE; - -out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - cleanup_association_attempt (self, TRUE); - wake_on_wlan_restore (self); - } + return NM_ACT_STAGE_RETURN_POSTPONE; - if (config) { - /* Supplicant interface object refs the config; we no longer care about - * it after this function. - */ - g_object_unref (config); - } - return ret; +out_fail: + cleanup_association_attempt (self, TRUE); + wake_on_wlan_restore (self); + return NM_ACT_STAGE_RETURN_FAILURE; } static NMActStageReturn @@ -3033,7 +3104,7 @@ activation_success_handler (NMDevice *device) update_seen_bssids_cache (self, priv->current_ap); /* Reset scan interval to something reasonable */ - priv->scan_interval = SCAN_INTERVAL_MIN + (SCAN_INTERVAL_STEP * 2); + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN + (SCAN_INTERVAL_SEC_STEP * 2); } static void @@ -3053,10 +3124,9 @@ device_state_changed (NMDevice *device, /* Clean up the supplicant interface because in these states the * device cannot be used. */ - if (priv->sup_iface) - supplicant_interface_release (self); + supplicant_interface_release (self); - nm_clear_g_source (&priv->periodic_source_id); + nm_clear_g_source (&priv->periodic_update_id); cleanup_association_attempt (self, TRUE); cleanup_supplicant_failures (self); @@ -3095,7 +3165,7 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_DISCONNECTED: /* Kick off a scan to get latest results */ - priv->scan_interval = SCAN_INTERVAL_MIN; + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN; request_wireless_scan (self, FALSE, FALSE, NULL); break; default: @@ -3109,7 +3179,7 @@ device_state_changed (NMDevice *device, static gboolean get_enabled (NMDevice *device) { - return NM_DEVICE_WIFI_GET_PRIVATE ((NMDeviceWifi *) device)->enabled; + return NM_DEVICE_WIFI_GET_PRIVATE (device)->enabled; } static void @@ -3155,8 +3225,7 @@ set_enabled (NMDevice *device, gboolean enabled) /* Re-initialize the supplicant interface and wait for it to be ready */ cleanup_supplicant_failures (self); - if (priv->sup_iface) - supplicant_interface_release (self); + supplicant_interface_release (self); supplicant_interface_acquire (self); _LOGD (LOGD_WIFI, "enable waiting on supplicant state"); @@ -3251,13 +3320,13 @@ get_property (GObject *object, guint prop_id, nm_dbus_utils_g_value_set_object_path (value, priv->current_ap); break; case PROP_SCANNING: - g_value_set_boolean (value, priv->is_scanning); + g_value_set_boolean (value, nm_device_wifi_get_scanning (self)); break; case PROP_LAST_SCAN: g_value_set_int64 (value, - priv->last_scan > 0 - ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NS_PER_MSEC) - : (gint64) -1); + priv->last_scan_msec > 0 + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan_msec, NM_UTILS_NSEC_PER_MSEC) + : (gint64) -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -3291,6 +3360,8 @@ nm_device_wifi_init (NMDeviceWifi *self) NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); c_list_init (&priv->aps_lst_head); + c_list_init (&priv->scanning_prohibited_lst_head); + priv->aps_idx_by_supplicant_path = g_hash_table_new (nm_direct_hash, NULL); priv->hidden_probe_scan_warn = TRUE; priv->mode = NM_802_11_MODE_INFRA; @@ -3331,7 +3402,9 @@ dispose (GObject *object) NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - nm_clear_g_source (&priv->periodic_source_id); + nm_assert (c_list_is_empty (&priv->scanning_prohibited_lst_head)); + + nm_clear_g_source (&priv->periodic_update_id); wifi_secrets_cancel (self); @@ -3359,6 +3432,9 @@ finalize (GObject *object) NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); nm_assert (c_list_is_empty (&priv->aps_lst_head)); + nm_assert (g_hash_table_size (priv->aps_idx_by_supplicant_path) == 0); + + g_hash_table_unref (priv->aps_idx_by_supplicant_path); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3406,8 +3482,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) device_class->state_changed = device_state_changed; - klass->scanning_prohibited = scanning_prohibited; - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_WIFI_MODE, "", "", NM_802_11_MODE_UNKNOWN, @@ -3454,14 +3528,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - signals[SCANNING_PROHIBITED] = - g_signal_new (NM_DEVICE_WIFI_SCANNING_PROHIBITED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceWifiClass, scanning_prohibited), - NULL, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); - signals[P2P_DEVICE_CREATED] = g_signal_new (NM_DEVICE_WIFI_P2P_DEVICE_CREATED, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index aaf47143..c9fce4e2 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -24,7 +24,6 @@ #define NM_DEVICE_WIFI_SCANNING "scanning" #define NM_DEVICE_WIFI_LAST_SCAN "last-scan" -#define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited" #define NM_DEVICE_WIFI_P2P_DEVICE_CREATED "p2p-device-created" typedef struct _NMDeviceWifi NMDeviceWifi; @@ -40,4 +39,12 @@ void _nm_device_wifi_request_scan (NMDeviceWifi *self, GVariant *options, GDBusMethodInvocation *invocation); +GPtrArray *nmtst_ssids_options_to_ptrarray (GVariant *value, GError **error); + +gboolean nm_device_wifi_get_scanning (NMDeviceWifi *self); + +void nm_device_wifi_scanning_prohibited_track (NMDeviceWifi *self, + gpointer tag, + gboolean temporarily_prohibited); + #endif /* __NETWORKMANAGER_DEVICE_WIFI_H__ */ diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index 470cb1c9..39c863a3 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -874,7 +874,8 @@ nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, } GDBusProxy * -nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, +nm_iwd_manager_get_dbus_interface (NMIwdManager *self, + const char *path, const char *name) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index ee7dc236..e427c86f 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -10,15 +10,16 @@ #include <stdlib.h> -#include "nm-setting-wireless.h" - -#include "nm-wifi-utils.h" #include "NetworkManagerUtils.h" -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" #include "devices/nm-device.h" +#include "nm-core-internal.h" #include "nm-dbus-manager.h" +#include "nm-glib-aux/nm-ref-string.h" +#include "nm-setting-wireless.h" +#include "nm-utils.h" +#include "nm-wifi-utils.h" +#include "platform/nm-platform.h" +#include "supplicant/nm-supplicant-interface.h" #define PROTO_WPA "wpa" #define PROTO_RSN "rsn" @@ -39,8 +40,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiAP, ); struct _NMWifiAPPrivate { - char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ - /* Scanned or cached values */ GBytes * ssid; char * address; @@ -49,6 +48,9 @@ struct _NMWifiAPPrivate { guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ + gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). + * Note that this value might be negative! */ + NM80211ApFlags flags; /* General flags */ NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */ NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */ @@ -58,7 +60,6 @@ struct _NMWifiAPPrivate { /* Non-scanned attributes */ bool fake:1; /* Whether or not the AP is from a scan */ bool hotspot:1; /* Whether the AP is a local device's hotspot network */ - gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ }; typedef struct _NMWifiAPPrivate NMWifiAPPrivate; @@ -73,14 +74,6 @@ G_DEFINE_TYPE (NMWifiAP, nm_wifi_ap, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ -const char * -nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) -{ - g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); - - return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path; -} - GBytes * nm_wifi_ap_get_ssid (const NMWifiAP *ap) { @@ -148,11 +141,7 @@ nm_wifi_ap_set_ssid (NMWifiAP *ap, GBytes *ssid) static gboolean nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->flags != flags) { priv->flags = flags; @@ -165,11 +154,8 @@ nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags) static gboolean nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->wpa_flags != flags) { priv->wpa_flags = flags; _notify (ap, PROP_WPA_FLAGS); @@ -181,11 +167,8 @@ nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) static gboolean nm_wifi_ap_set_rsn_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->rsn_flags != flags) { priv->rsn_flags = flags; _notify (ap, PROP_RSN_FLAGS); @@ -203,11 +186,9 @@ nm_wifi_ap_get_address (const NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 *addr /* ETH_ALEN bytes */) +nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 addr[static 6 /* ETH_ALEN */]) { - NMWifiAPPrivate *priv; - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if ( !priv->address || !nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1)) { @@ -241,16 +222,14 @@ nm_wifi_ap_get_mode (NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode) +nm_wifi_ap_set_mode (NMWifiAP *ap, NM80211Mode mode) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC - || mode == NM_802_11_MODE_INFRA - || mode == NM_802_11_MODE_MESH, FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - priv = NM_WIFI_AP_GET_PRIVATE (ap); + nm_assert (NM_IN_SET (mode, NM_802_11_MODE_UNKNOWN, + NM_802_11_MODE_ADHOC, + NM_802_11_MODE_INFRA, + NM_802_11_MODE_MESH)); if (priv->mode != mode) { priv->mode = mode; @@ -277,13 +256,9 @@ nm_wifi_ap_get_strength (NMWifiAP *ap) } gboolean -nm_wifi_ap_set_strength (NMWifiAP *ap, const gint8 strength) +nm_wifi_ap_set_strength (NMWifiAP *ap, gint8 strength) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->strength != strength) { priv->strength = strength; @@ -303,13 +278,9 @@ nm_wifi_ap_get_freq (NMWifiAP *ap) gboolean nm_wifi_ap_set_freq (NMWifiAP *ap, - const guint32 freq) + guint32 freq) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->freq != freq) { priv->freq = freq; @@ -378,16 +349,12 @@ nm_wifi_ap_get_flags (const NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen) +nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen_msec) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - if (priv->last_seen != last_seen) { - priv->last_seen = last_seen; + if (priv->last_seen_msec != last_seen_msec) { + priv->last_seen_msec = last_seen_msec; _notify (ap, PROP_LAST_SEEN); return TRUE; } @@ -402,501 +369,53 @@ nm_wifi_ap_get_metered (const NMWifiAP *self) /*****************************************************************************/ -static NM80211ApSecurityFlags -security_from_vardict (GVariant *security) -{ - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - const char **array, *tmp; - - g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE); - - if ( g_variant_lookup (security, "KeyMgmt", "^a&s", &array) - && array) { - if (g_strv_contains (array, "wpa-psk") || - g_strv_contains (array, "wpa-ft-psk")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - if (g_strv_contains (array, "wpa-eap") || - g_strv_contains (array, "wpa-ft-eap") || - g_strv_contains (array, "wpa-fils-sha256") || - g_strv_contains (array, "wpa-fils-sha384")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; - if (g_strv_contains (array, "sae")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; - g_free (array); - } - - if ( g_variant_lookup (security, "Pairwise", "^a&s", &array) - && array) { - if (g_strv_contains (array, "tkip")) - flags |= NM_802_11_AP_SEC_PAIR_TKIP; - if (g_strv_contains (array, "ccmp")) - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - g_free (array); - } - - if (g_variant_lookup (security, "Group", "&s", &tmp)) { - if (strcmp (tmp, "wep40") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP40; - if (strcmp (tmp, "wep104") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP104; - if (strcmp (tmp, "tkip") == 0) - flags |= NM_802_11_AP_SEC_GROUP_TKIP; - if (strcmp (tmp, "ccmp") == 0) - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - } - - return flags; -} - -/*****************************************************************************/ - -static guint32 -get_max_rate_ht_20 (int mcs) -{ - switch (mcs) { - case 0: return 6500000; - case 1: - case 8: return 13000000; - case 2: - case 16: return 19500000; - case 3: - case 9: - case 24: return 26000000; - case 4: - case 10: - case 17: return 39000000; - case 5: - case 11: - case 25: return 52000000; - case 6: - case 18: return 58500000; - case 7: return 65000000; - case 12: - case 19: - case 26: return 78000000; - case 13: - case 27: return 104000000; - case 14: - case 20: return 117000000; - case 15: return 130000000; - case 21: - case 28: return 156000000; - case 22: return 175500000; - case 23: return 195000000; - case 29: return 208000000; - case 30: return 234000000; - case 31: return 260000000; - } - return 0; -} - -static guint32 -get_max_rate_ht_40 (int mcs) -{ - switch (mcs) { - case 0: return 13500000; - case 1: - case 8: return 27000000; - case 2: return 40500000; - case 3: - case 9: - case 24: return 54000000; - case 4: - case 10: - case 17: return 81000000; - case 5: - case 11: - case 25: return 108000000; - case 6: - case 18: return 121500000; - case 7: return 135000000; - case 12: - case 19: - case 26: return 162000000; - case 13: - case 27: return 216000000; - case 14: - case 20: return 243000000; - case 15: return 270000000; - case 16: return 40500000; - case 21: - case 28: return 324000000; - case 22: return 364500000; - case 23: return 405000000; - case 29: return 432000000; - case 30: return 486000000; - case 31: return 540000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss1 (int mcs) -{ - switch (mcs) { - case 0: return 29300000; - case 1: return 58500000; - case 2: return 87800000; - case 3: return 117000000; - case 4: return 175500000; - case 5: return 234000000; - case 6: return 263300000; - case 7: return 292500000; - case 8: return 351000000; - case 9: return 390000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss2 (int mcs) -{ - switch (mcs) { - case 0: return 58500000; - case 1: return 117000000; - case 2: return 175500000; - case 3: return 234000000; - case 4: return 351000000; - case 5: return 468000000; - case 6: return 526500000; - case 7: return 585000000; - case 8: return 702000000; - case 9: return 780000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss3 (int mcs) -{ - switch (mcs) { - case 0: return 87800000; - case 1: return 175500000; - case 2: return 263300000; - case 3: return 351000000; - case 4: return 526500000; - case 5: return 702000000; - case 6: return 0; - case 7: return 877500000; - case 8: return 105300000; - case 9: return 117000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss1 (int mcs) -{ - switch (mcs) { - case 0: return 58500000; - case 1: return 117000000; - case 2: return 175500000; - case 3: return 234000000; - case 4: return 351000000; - case 5: return 468000000; - case 6: return 526500000; - case 7: return 585000000; - case 8: return 702000000; - case 9: return 780000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss2 (int mcs) -{ - switch (mcs) { - case 0: return 117000000; - case 1: return 234000000; - case 2: return 351000000; - case 3: return 468000000; - case 4: return 702000000; - case 5: return 936000000; - case 6: return 1053000000; - case 7: return 1170000000; - case 8: return 1404000000; - case 9: return 1560000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss3 (int mcs) -{ - switch (mcs) { - case 0: return 175500000; - case 1: return 351000000; - case 2: return 526500000; - case 3: return 702000000; - case 4: return 1053000000; - case 5: return 1404000000; - case 6: return 1579500000; - case 7: return 1755000000; - case 8: return 2106000000; - case 9: return 0; - } - return 0; -} - -static gboolean -get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) -{ - guint32 i; - guint8 ht_cap_info; - const guint8 *supported_mcs_set; - guint32 rate; - - /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf - * https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ - */ - - if (len != 26) - return FALSE; - - ht_cap_info = bytes[0]; - supported_mcs_set = &bytes[3]; - *out_maxrate = 0; - - /* Find the maximum supported mcs rate */ - for (i = 0; i <= 76; i++) { - unsigned int mcs_octet = i / 8; - unsigned int MCS_RATE_BIT = 1 << i % 8; - - if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) { - /* Check for 40Mhz wide channel support */ - if (ht_cap_info & (1 << 1)) - rate = get_max_rate_ht_40 (i); - else - rate = get_max_rate_ht_20 (i); - - if (rate > *out_maxrate) - *out_maxrate = rate; - } - } - - return TRUE; -} - -static gboolean -get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate) -{ - guint32 mcs, m; - guint8 vht_cap, tx_map; - - /* https://tda802dot11.blogspot.it/2014/10/vht-capabilities-element-vht.html - * http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames */ - - if (len != 12) - return FALSE; - - vht_cap = bytes[0]; - tx_map = bytes[8]; - - /* Check for mcs rates 8 and 9 support */ - if (tx_map & 0x2a) - mcs = 9; - else if (tx_map & 0x15) - mcs = 8; - else - mcs = 7; - - /* Check for 160Mhz wide channel support and - * spatial stream support */ - if (vht_cap & (1 << 2)) { - if (tx_map & 0x30) - m = get_max_rate_vht_160_ss3 (mcs); - else if (tx_map & 0x0C) - m = get_max_rate_vht_160_ss2 (mcs); - else - m = get_max_rate_vht_160_ss1 (mcs); - } else { - if (tx_map & 0x30) - m = get_max_rate_vht_80_ss3 (mcs); - else if (tx_map & 0x0C) - m = get_max_rate_vht_80_ss2 (mcs); - else - m = get_max_rate_vht_80_ss1 (mcs); - } - - *out_maxrate = m; - return TRUE; -} - -/* Management Frame Information Element IDs, ieee80211_eid */ -#define WLAN_EID_HT_CAPABILITY 45 -#define WLAN_EID_VHT_CAPABILITY 191 -#define WLAN_EID_VENDOR_SPECIFIC 221 - -static void -parse_ies (const guint8 *bytes, gsize len, guint32 *out_max_rate, gboolean *out_metered) -{ - guint8 id, elem_len; - guint32 m; - - *out_max_rate = 0; - *out_metered = FALSE; - - while (len) { - if (len < 2) - break; - - id = *bytes++; - elem_len = *bytes++; - len -= 2; - - if (elem_len > len) - break; - - switch (id) { - case WLAN_EID_HT_CAPABILITY: - if (get_max_rate_ht (bytes, elem_len, &m)) - *out_max_rate = NM_MAX (*out_max_rate, m); - break; - case WLAN_EID_VHT_CAPABILITY: - if (get_max_rate_vht (bytes, elem_len, &m)) - *out_max_rate = NM_MAX (*out_max_rate, m); - break; - case WLAN_EID_VENDOR_SPECIFIC: - if ( len == 8 - && bytes[0] == 0x00 /* OUI: Microsoft */ - && bytes[1] == 0x50 - && bytes[2] == 0xf2 - && bytes[3] == 0x11) /* OUI type: Network cost */ - *out_metered = (bytes[7] > 1); /* Cost level > 1 */ - break; - } - - len -= elem_len; - bytes += elem_len; - } -} - -/*****************************************************************************/ - gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, - const char *supplicant_path, - GVariant *properties) + const NMSupplicantBssInfo *bss_info) { NMWifiAPPrivate *priv; - const guint8 *bytes; - GVariant *v; - gsize len; - gsize i; - gboolean b = FALSE; - const char *s; - gint16 i16; - guint16 u16; gboolean changed = FALSE; - gboolean metered; - guint32 max_rate, rate; g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail (properties, FALSE); + g_return_val_if_fail (bss_info, FALSE); + nm_assert (NM_IS_REF_STRING (bss_info->bss_path)); priv = NM_WIFI_AP_GET_PRIVATE (ap); - g_object_freeze_notify (G_OBJECT (ap)); - - if (g_variant_lookup (properties, "Privacy", "b", &b) && b) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); - - v = g_variant_lookup_value (properties, "WPS", G_VARIANT_TYPE_VARDICT); - if (v) { - if (g_variant_lookup (v, "Type", "&s", &s)) { - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS); - if (strcmp (s, "pbc") == 0) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PBC); - else if (strcmp (s, "pin") == 0) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PIN); - } - g_variant_unref (v); - } - - if (g_variant_lookup (properties, "Mode", "&s", &s)) { - if (!g_strcmp0 (s, "infrastructure")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); - else if (!g_strcmp0 (s, "ad-hoc")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); - else if (!g_strcmp0 (s, "mesh")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH); - } - - if (g_variant_lookup (properties, "Signal", "n", &i16)) - changed |= nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (i16)); - - if (g_variant_lookup (properties, "Frequency", "q", &u16)) - changed |= nm_wifi_ap_set_freq (ap, u16); - - v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - len = MIN (32, len); + nm_assert ( !ap->_supplicant_path + || ap->_supplicant_path == bss_info->bss_path); - /* Stupid ieee80211 layer uses <hidden> */ - if ( bytes - && len - && !( NM_IN_SET (len, 8, 9) - && memcmp (bytes, "<hidden>", len) == 0) - && !nm_utils_is_empty_ssid (bytes, len)) { - /* good */ - } else - len = 0; - - changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len); - - g_variant_unref (v); - } + g_object_freeze_notify (G_OBJECT (ap)); - v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - if ( len == ETH_ALEN - && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 - && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) - changed |= nm_wifi_ap_set_address_bin (ap, bytes); - g_variant_unref (v); + if (!ap->_supplicant_path) { + ap->_supplicant_path = nm_ref_string_ref (bss_info->bss_path); + changed = TRUE; } - max_rate = 0; - v = g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au")); - if (v) { - const guint32 *rates = g_variant_get_fixed_array (v, &len, sizeof (guint32)); + changed |= nm_wifi_ap_set_flags (ap, bss_info->ap_flags); + changed |= nm_wifi_ap_set_mode (ap, bss_info->mode); + changed |= nm_wifi_ap_set_strength (ap, bss_info->signal_percent); + changed |= nm_wifi_ap_set_freq (ap, bss_info->frequency); + changed |= nm_wifi_ap_set_ssid (ap, bss_info->ssid); - for (i = 0; i < len; i++) - max_rate = NM_MAX (max_rate, rates[i]); - g_variant_unref (v); - } - v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - parse_ies (bytes, len, &rate, &metered); - max_rate = NM_MAX (max_rate, rate); - g_variant_unref (v); - priv->metered = metered; + if (bss_info->bssid_valid) + changed |= nm_wifi_ap_set_address_bin (ap, bss_info->bssid); + else { + /* we don't actually clear the value. */ } - if (max_rate) - changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); + changed |= nm_wifi_ap_set_max_bitrate (ap, bss_info->max_rate); - v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); - if (v) { - changed |= nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); - g_variant_unref (v); + if (priv->metered != bss_info->metered) { + priv->metered = bss_info->metered; + changed = TRUE; } - v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); - if (v) { - changed |= nm_wifi_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v)); - g_variant_unref (v); - } + changed |= nm_wifi_ap_set_wpa_flags (ap, bss_info->wpa_flags); + changed |= nm_wifi_ap_set_rsn_flags (ap, bss_info->rsn_flags); - if (!priv->supplicant_path) { - priv->supplicant_path = g_strdup (supplicant_path); - changed = TRUE; - } + changed |= nm_wifi_ap_set_last_seen (ap, bss_info->last_seen_msec); - changed |= nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); changed |= nm_wifi_ap_set_fake (ap, FALSE); g_object_thaw_notify (G_OBJECT (ap)); @@ -984,20 +503,22 @@ const char * nm_wifi_ap_to_string (const NMWifiAP *self, char *str_buf, gulong buf_len, - gint32 now_s) + gint64 now_msec) { const NMWifiAPPrivate *priv; const char *supplicant_id = "-"; const char *export_path; guint32 chan; gs_free char *ssid_to_free = NULL; + char str_buf_ts[100]; g_return_val_if_fail (NM_IS_WIFI_AP (self), NULL); priv = NM_WIFI_AP_GET_PRIVATE (self); + chan = nm_utils_wifi_freq_to_channel (priv->freq); - if (priv->supplicant_path) - supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + if (self->_supplicant_path) + supplicant_id = strrchr (self->_supplicant_path->str, '/') ?: supplicant_id; export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); if (export_path) @@ -1005,8 +526,10 @@ nm_wifi_ap_to_string (const NMWifiAP *self, else export_path = "/"; + nm_utils_get_monotonic_timestamp_msec_cached (&now_msec); + g_snprintf (str_buf, buf_len, - "%17s %-35s [ %c %3u %3u%% %c%c W:%04X R:%04X ] %3us sup:%s [nm:%s]", + "%17s %-35s [ %c %3u %3u%% %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", priv->address ?: "(none)", (ssid_to_free = _nm_utils_ssid_to_string (priv->ssid)), (priv->mode == NM_802_11_MODE_ADHOC @@ -1024,7 +547,12 @@ nm_wifi_ap_to_string (const NMWifiAP *self, priv->metered ? 'M' : '_', priv->wpa_flags & 0xFFFF, priv->rsn_flags & 0xFFFF, - priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, + priv->last_seen_msec != G_MININT64 + ? nm_sprintf_buf (str_buf_ts, + "%3u.%03us", + (guint) ((now_msec - priv->last_seen_msec) / 1000), + (guint) ((now_msec - priv->last_seen_msec) % 1000)) + : " ", supplicant_id, export_path); return str_buf; @@ -1177,9 +705,9 @@ get_property (GObject *object, guint prop_id, break; case PROP_LAST_SEEN: g_value_set_int (value, - priv->last_seen > 0 - ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) - : -1); + priv->last_seen_msec != G_MININT64 + ? (int) NM_MAX (nm_utils_monotonic_timestamp_as_boottime (priv->last_seen_msec, NM_UTILS_NSEC_PER_MSEC) / 1000, 1) + : -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1204,26 +732,16 @@ nm_wifi_ap_init (NMWifiAP *self) priv->flags = NM_802_11_AP_FLAGS_NONE; priv->wpa_flags = NM_802_11_AP_SEC_NONE; priv->rsn_flags = NM_802_11_AP_SEC_NONE; - priv->last_seen = -1; + priv->last_seen_msec = G_MININT64; } NMWifiAP * -nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +nm_wifi_ap_new_from_properties (const NMSupplicantBssInfo *bss_info) { NMWifiAP *ap; - g_return_val_if_fail (supplicant_path != NULL, NULL); - g_return_val_if_fail (properties != NULL, NULL); - - ap = (NMWifiAP *) g_object_new (NM_TYPE_WIFI_AP, NULL); - nm_wifi_ap_update_from_properties (ap, supplicant_path, properties); - - /* ignore APs with invalid or missing BSSIDs */ - if (!nm_wifi_ap_get_address (ap)) { - g_object_unref (ap); - return NULL; - } - + ap = g_object_new (NM_TYPE_WIFI_AP, NULL); + nm_wifi_ap_update_from_properties (ap, bss_info); return ap; } @@ -1349,7 +867,7 @@ finalize (GObject *object) nm_assert (!self->wifi_device); nm_assert (c_list_is_empty (&self->aps_lst)); - g_free (priv->supplicant_path); + nm_ref_string_unref (self->_supplicant_path); if (priv->ssid) g_bytes_unref (priv->ssid); g_free (priv->address); @@ -1394,7 +912,8 @@ nm_wifi_ap_class_init (NMWifiAPClass *ap_class) | NM_802_11_AP_SEC_GROUP_CCMP \ | NM_802_11_AP_SEC_KEY_MGMT_PSK \ | NM_802_11_AP_SEC_KEY_MGMT_802_1X \ - | NM_802_11_AP_SEC_KEY_MGMT_SAE ) + | NM_802_11_AP_SEC_KEY_MGMT_SAE \ + | NM_802_11_AP_SEC_KEY_MGMT_OWE ) GObjectClass *object_class = G_OBJECT_CLASS (ap_class); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ap_class); @@ -1515,20 +1034,6 @@ nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, return NULL; } -NMWifiAP * -nm_wifi_aps_find_by_supplicant_path (const CList *aps_lst_head, const char *path) -{ - NMWifiAP *ap; - - g_return_val_if_fail (path != NULL, NULL); - - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - if (nm_streq0 (path, nm_wifi_ap_get_supplicant_path (ap))) - return ap; - } - return NULL; -} - /*****************************************************************************/ NMWifiAP * diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 472dfdf9..1bf4e604 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -33,20 +33,21 @@ typedef struct { NMDBusObject parent; NMDevice *wifi_device; CList aps_lst; + NMRefString *_supplicant_path; struct _NMWifiAPPrivate *_priv; } NMWifiAP; +struct _NMSupplicantBssInfo; + typedef struct _NMWifiAPClass NMWifiAPClass; GType nm_wifi_ap_get_type (void); -NMWifiAP * nm_wifi_ap_new_from_properties (const char *supplicant_path, - GVariant *properties); -NMWifiAP * nm_wifi_ap_new_fake_from_connection (NMConnection *connection); +NMWifiAP *nm_wifi_ap_new_from_properties (const struct _NMSupplicantBssInfo *bss_info); +NMWifiAP *nm_wifi_ap_new_fake_from_connection (NMConnection *connection); -gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, - const char *supplicant_path, - GVariant *properties); +gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, + const struct _NMSupplicantBssInfo *bss_info); gboolean nm_wifi_ap_check_compatible (NMWifiAP *self, NMConnection *connection); @@ -56,7 +57,14 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, gboolean lock_bssid, GError **error); -const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); +static inline NMRefString * +nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) +{ + g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); + + return ap->_supplicant_path; +} + GBytes *nm_wifi_ap_get_ssid (const NMWifiAP *ap); gboolean nm_wifi_ap_set_ssid_arr (NMWifiAP *ap, const guint8 *ssid, @@ -86,7 +94,7 @@ gboolean nm_wifi_ap_get_metered (const NMWifiAP *self); const char *nm_wifi_ap_to_string (const NMWifiAP *self, char *str_buf, gulong buf_len, - gint32 now_s); + gint64 now_msec); const char **nm_wifi_aps_get_paths (const CList *aps_lst_head, gboolean include_without_ssid); @@ -94,8 +102,6 @@ const char **nm_wifi_aps_get_paths (const CList *aps_lst_head, NMWifiAP *nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, NMConnection *connection); -NMWifiAP *nm_wifi_aps_find_by_supplicant_path (const CList *aps_lst_head, const char *path); - NMWifiAP *nm_wifi_ap_lookup_for_device (NMDevice *device, const char *exported_path); #endif /* __NM_WIFI_AP_H__ */ diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 821460a5..9b87bbbf 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -95,7 +95,7 @@ create_device (NMDeviceFactory *factory, iface, NM_PRINT_FMT_QUOTE_STRING (backend), WITH_IWD ? " (iwd support enabled)" : ""); - if (!backend || !strcasecmp (backend, "wpa_supplicant")) { + if (!backend || !g_ascii_strcasecmp (backend, "wpa_supplicant")) { NMDevice *device; NMDeviceWifiCapabilities capabilities; NM80211Mode mode; @@ -129,7 +129,7 @@ create_device (NMDeviceFactory *factory, return device; } #if WITH_IWD - else if (!strcasecmp (backend, "iwd")) + else if (!g_ascii_strcasecmp (backend, "iwd")) return nm_device_iwd_new (iface); #endif diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c index f8da0046..c58bd95e 100644 --- a/src/devices/wifi/nm-wifi-p2p-peer.c +++ b/src/devices/wifi/nm-wifi-p2p-peer.c @@ -9,15 +9,16 @@ #include <stdlib.h> -#include "nm-setting-wireless.h" - -#include "nm-wifi-utils.h" #include "NetworkManagerUtils.h" -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" #include "devices/nm-device.h" +#include "nm-core-internal.h" #include "nm-dbus-manager.h" +#include "nm-glib-aux/nm-ref-string.h" +#include "nm-setting-wireless.h" +#include "nm-utils.h" +#include "nm-wifi-utils.h" +#include "platform/nm-platform.h" +#include "supplicant/nm-supplicant-types.h" /*****************************************************************************/ @@ -28,7 +29,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer, PROP_MODEL_NUMBER, PROP_SERIAL, PROP_WFD_IES, - PROP_GROUPS, PROP_HW_ADDRESS, PROP_STRENGTH, PROP_LAST_SEEN, @@ -36,7 +36,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer, ); struct _NMWifiP2PPeerPrivate { - char *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ + NMRefString *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ /* Scanned or cached values */ char * name; @@ -55,7 +55,7 @@ struct _NMWifiP2PPeerPrivate { NM80211ApFlags flags; /* General flags */ /* Non-scanned attributes */ - gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ + gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_sec()) */ }; typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate; @@ -151,7 +151,7 @@ nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer) { g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); - return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path; + return nm_ref_string_get_str (NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path); } const char * @@ -163,18 +163,12 @@ nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *name) +nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (name, priv->name) == 0) + if (!nm_utils_strdup_reset (&priv->name, str)) return FALSE; - - g_clear_pointer (&priv->name, g_free); - if (name) - priv->name = g_strdup (name); - _notify (peer, PROP_NAME); return TRUE; } @@ -188,18 +182,12 @@ nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *manufacturer) +nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (manufacturer, priv->manufacturer) == 0) + if (!nm_utils_strdup_reset (&priv->manufacturer, str)) return FALSE; - - g_clear_pointer (&priv->manufacturer, g_free); - if (manufacturer) - priv->manufacturer = g_strdup (manufacturer); - _notify (peer, PROP_MANUFACTURER); return TRUE; } @@ -213,18 +201,12 @@ nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *model) +nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (model, priv->model) == 0) + if (!nm_utils_strdup_reset (&priv->model, str)) return FALSE; - - g_clear_pointer (&priv->model, g_free); - if (model) - priv->model = g_strdup (model); - _notify (peer, PROP_MODEL); return TRUE; } @@ -238,18 +220,12 @@ nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *model_number) +nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (model_number, priv->model_number) == 0) + if (!nm_utils_strdup_reset (&priv->model_number, str)) return FALSE; - - g_clear_pointer (&priv->model_number, g_free); - if (model_number) - priv->model_number = g_strdup (model_number); - _notify (peer, PROP_MODEL_NUMBER); return TRUE; } @@ -263,18 +239,12 @@ nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *serial) +nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (serial, priv->serial) == 0) + if (!nm_utils_strdup_reset (&priv->serial, str)) return FALSE; - - g_clear_pointer (&priv->serial, g_free); - if (serial) - priv->serial = g_strdup (serial); - _notify (peer, PROP_SERIAL); return TRUE; } @@ -291,6 +261,7 @@ gboolean nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, GBytes *wfd_ies) { NMWifiP2PPeerPrivate *priv; + gs_unref_bytes GBytes *wfd_ies_old = NULL; g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); @@ -299,7 +270,7 @@ nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, GBytes *wfd_ies) if (nm_gbytes_equal0 (priv->wfd_ies, wfd_ies)) return FALSE; - g_bytes_unref (priv->wfd_ies); + wfd_ies_old = g_steal_pointer (&priv->wfd_ies); priv->wfd_ies = wfd_ies ? g_bytes_ref (wfd_ies) : NULL; _notify (peer, PROP_WFD_IES); @@ -311,27 +282,7 @@ nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer) { g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); - return (const char * const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups; -} - -static gboolean -nm_wifi_p2p_peer_set_groups (NMWifiP2PPeer *peer, const char** groups) -{ - NMWifiP2PPeerPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - g_return_val_if_fail (groups != NULL, FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - - if (_nm_utils_strv_equal (priv->groups, (char **) groups)) - return FALSE; - - g_strfreev (priv->groups); - priv->groups = g_strdupv ((char**) groups); - - _notify (peer, PROP_GROUPS); - return TRUE; + return (const char *const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups; } const char * @@ -382,11 +333,7 @@ nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer) gboolean nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer, const gint8 strength) { - NMWifiP2PPeerPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); if (priv->strength != strength) { priv->strength = strength; @@ -426,80 +373,42 @@ nm_wifi_p2p_peer_set_last_seen (NMWifiP2PPeer *peer, gint32 last_seen) gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, - const char *supplicant_path, - GVariant *properties) + const NMSupplicantPeerInfo *peer_info) { NMWifiP2PPeerPrivate *priv; - const guint8 *bytes; - GVariant *v; - gsize len; - const char *s; - const char **sv; - gint32 i32; gboolean changed = FALSE; g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - g_return_val_if_fail (properties, FALSE); + g_return_val_if_fail (peer_info, FALSE); + nm_assert (NM_IS_REF_STRING (peer_info->peer_path)); priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_object_freeze_notify (G_OBJECT (peer)); - - if (g_variant_lookup (properties, "level", "i", &i32)) - changed |= nm_wifi_p2p_peer_set_strength (peer, nm_wifi_utils_level_to_quality (i32)); - - if (g_variant_lookup (properties, "DeviceName", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_name (peer, s); - - if (g_variant_lookup (properties, "Manufacturer", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_manufacturer (peer, s); - - if (g_variant_lookup (properties, "Model", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_model (peer, s); - - if (g_variant_lookup (properties, "ModelNumber", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_model_number (peer, s); - - if (g_variant_lookup (properties, "Serial", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_serial (peer, s); + nm_assert ( !priv->supplicant_path + || priv->supplicant_path == peer_info->peer_path); - v = g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - if ( len == ETH_ALEN - && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 - && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) - changed |= nm_wifi_p2p_peer_set_address_bin (peer, bytes); - g_variant_unref (v); - } - - /* The IEs property contains the WFD R1 subelements */ - v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); - if (v) { - gs_unref_bytes GBytes *b = NULL; - - bytes = g_variant_get_fixed_array (v, &len, 1); - b = g_bytes_new (bytes, len); - changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, b); - g_variant_unref (v); - } - - v = g_variant_lookup_value (properties, "Groups", G_VARIANT_TYPE_OBJECT_PATH_ARRAY); - if (v) { - sv = g_variant_get_objv (v, NULL); - changed |= nm_wifi_p2p_peer_set_groups (peer, sv); - g_free (sv); - } - - /*if (max_rate) - changed |= nm_wifi_p2p_peer_set_max_bitrate (peer, max_rate / 1000);*/ + g_object_freeze_notify (G_OBJECT (peer)); if (!priv->supplicant_path) { - priv->supplicant_path = g_strdup (supplicant_path); + priv->supplicant_path = nm_ref_string_ref (peer_info->peer_path); changed = TRUE; } - changed |= nm_wifi_p2p_peer_set_last_seen (peer, nm_utils_get_monotonic_timestamp_s ()); + changed |= nm_wifi_p2p_peer_set_strength (peer, peer_info->signal_percent); + changed |= nm_wifi_p2p_peer_set_name (peer, peer_info->device_name); + changed |= nm_wifi_p2p_peer_set_manufacturer (peer, peer_info->manufacturer); + changed |= nm_wifi_p2p_peer_set_model (peer, peer_info->model); + changed |= nm_wifi_p2p_peer_set_model_number (peer, peer_info->model_number); + changed |= nm_wifi_p2p_peer_set_serial (peer, peer_info->serial); + + if (peer_info->address_valid) + changed |= nm_wifi_p2p_peer_set_address_bin (peer, peer_info->address); + else { + /* we don't reset the address. */ + } + + changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, peer_info->ies); + changed |= nm_wifi_p2p_peer_set_last_seen (peer, peer_info->last_seen_msec / 1000u); g_object_thaw_notify (G_OBJECT (peer)); @@ -521,7 +430,7 @@ nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); if (priv->supplicant_path) - supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + supplicant_id = strrchr (priv->supplicant_path->str, '/') ?: supplicant_id; export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); if (export_path) @@ -537,7 +446,7 @@ nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, priv->model, priv->model_number, priv->serial, - priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, + priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec ()) - priv->last_seen) : -1, supplicant_id, export_path); @@ -601,12 +510,6 @@ get_property (GObject *object, guint prop_id, case PROP_WFD_IES: g_value_take_variant (value, nm_utils_gbytes_to_variant_ay (priv->wfd_ies)); break; - case PROP_GROUPS: - g_value_set_variant (value, - g_variant_new_strv ( (const char*const*) priv->groups - ?: NM_PTRARRAY_EMPTY (const char *), - -1)); - break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->address); break; @@ -616,7 +519,7 @@ get_property (GObject *object, guint prop_id, case PROP_LAST_SEEN: g_value_set_int (value, priv->last_seen > 0 - ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NSEC_PER_SEC) : -1); break; default: @@ -643,22 +546,14 @@ nm_wifi_p2p_peer_init (NMWifiP2PPeer *self) } NMWifiP2PPeer * -nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, GVariant *properties) +nm_wifi_p2p_peer_new_from_properties (const NMSupplicantPeerInfo *peer_info) { NMWifiP2PPeer *peer; - g_return_val_if_fail (supplicant_path != NULL, NULL); - g_return_val_if_fail (properties != NULL, NULL); - - peer = (NMWifiP2PPeer *) g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL); - nm_wifi_p2p_peer_update_from_properties (peer, supplicant_path, properties); - - /* ignore peers with invalid or missing address */ - if (!nm_wifi_p2p_peer_get_address (peer)) { - g_object_unref (peer); - return NULL; - } + g_return_val_if_fail (peer_info, NULL); + peer = g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL); + nm_wifi_p2p_peer_update_from_properties (peer, peer_info); return peer; } @@ -671,7 +566,7 @@ finalize (GObject *object) nm_assert (!self->wifi_device); nm_assert (c_list_is_empty (&self->peers_lst)); - g_free (priv->supplicant_path); + nm_ref_string_unref (priv->supplicant_path); g_free (priv->name); g_free (priv->manufacturer); g_free (priv->model); @@ -688,6 +583,7 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( NM_DBUS_INTERFACE_WIFI_P2P_PEER, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( + /* Before 1.24, we wrongly exposed a property "Groups" of type "as". Don't reuse that property name. */ NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Flags", "u", NM_WIFI_P2P_PEER_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Name", "s", NM_WIFI_P2P_PEER_NAME), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Manufacturer", "s", NM_WIFI_P2P_PEER_MANUFACTURER), @@ -695,7 +591,6 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("ModelNumber", "s", NM_WIFI_P2P_PEER_MODEL_NUMBER), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Serial", "s", NM_WIFI_P2P_PEER_SERIAL), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("WfdIEs", "ay", NM_WIFI_P2P_PEER_WFD_IES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Groups", "as", NM_WIFI_P2P_PEER_GROUPS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_WIFI_P2P_PEER_HW_ADDRESS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Strength", "y", NM_WIFI_P2P_PEER_STRENGTH), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("LastSeen", "i", NM_WIFI_P2P_PEER_LAST_SEEN), @@ -756,12 +651,6 @@ nm_wifi_p2p_peer_class_init (NMWifiP2PPeerClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_GROUPS] = - g_param_spec_variant (NM_WIFI_P2P_PEER_GROUPS, "", "", - G_VARIANT_TYPE ("as"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HW_ADDRESS] = g_param_spec_string (NM_WIFI_P2P_PEER_HW_ADDRESS, "", "", NULL, diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h index 07f25cc1..59f9c5d2 100644 --- a/src/devices/wifi/nm-wifi-p2p-peer.h +++ b/src/devices/wifi/nm-wifi-p2p-peer.h @@ -24,7 +24,6 @@ #define NM_WIFI_P2P_PEER_MODEL_NUMBER "model-number" #define NM_WIFI_P2P_PEER_SERIAL "serial" #define NM_WIFI_P2P_PEER_WFD_IES "wfd-ies" -#define NM_WIFI_P2P_PEER_GROUPS "groups" #define NM_WIFI_P2P_PEER_HW_ADDRESS "hw-address" #define NM_WIFI_P2P_PEER_STRENGTH "strength" #define NM_WIFI_P2P_PEER_LAST_SEEN "last-seen" @@ -38,14 +37,14 @@ typedef struct { typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass; +struct _NMSupplicantPeerInfo; + GType nm_wifi_p2p_peer_get_type (void); -NMWifiP2PPeer * nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, - GVariant *properties); +NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties (const struct _NMSupplicantPeerInfo *peer_info); -gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, - const char *supplicant_path, - GVariant *properties); +gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, + const struct _NMSupplicantPeerInfo *peer_info); gboolean nm_wifi_p2p_peer_check_compatible (NMWifiP2PPeer *self, NMConnection *connection); diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index b9b7ec42..0903dc8b 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -759,6 +759,12 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); + } else if ( (key_mgmt && !strcmp (key_mgmt, "owe")) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE)) { + g_object_set (s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "owe", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NULL); } else if ( (key_mgmt && !strcmp (key_mgmt, "wpa-psk")) || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { @@ -780,25 +786,6 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, return TRUE; } -guint32 -nm_wifi_utils_level_to_quality (int val) -{ - if (val < 0) { - /* Assume dBm already; rough conversion: best = -40, worst = -100 */ - val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ - val = 100 - (int) ((100.0 * (double) val) / 60.0); - } else if (val > 110 && val < 256) { - /* assume old-style WEXT 8-bit unsigned signal level */ - val -= 256; /* subtract 256 to convert to dBm */ - val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ - val = 100 - (int) ((100.0 * (double) val) / 60.0); - } else { - /* Assume signal is a "quality" percentage */ - } - - return CLAMP (val, 0, 100); -} - gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid) { diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index 982080b9..505baa84 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -30,8 +30,6 @@ gboolean nm_wifi_utils_complete_connection (GBytes *ssid, gboolean lock_bssid, GError **error); -guint32 nm_wifi_utils_level_to_quality (int val); - gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid); NMIwdNetworkSecurity nm_wifi_connection_get_iwd_security (NMConnection *connection, diff --git a/src/devices/wifi/tests/test-devices-wifi.c b/src/devices/wifi/tests/test-devices-wifi.c index a960e7a2..bde36307 100644 --- a/src/devices/wifi/tests/test-devices-wifi.c +++ b/src/devices/wifi/tests/test-devices-wifi.c @@ -6,6 +6,7 @@ #include "nm-default.h" #include "devices/wifi/nm-wifi-utils.h" +#include "devices/wifi/nm-device-wifi.h" #include "nm-core-internal.h" #include "nm-test-utils-core.h" @@ -1337,6 +1338,60 @@ test_strength_all (void) /*****************************************************************************/ +static void +do_test_ssids_options_to_ptrarray (const char *const*ssids) +{ + GVariantBuilder builder; + gs_unref_variant GVariant *variant = NULL; + gs_unref_ptrarray GPtrArray *ssids_arr = NULL; + gs_free_error GError *error = NULL; + gsize len; + gsize i; + + g_assert (ssids); + + len = NM_PTRARRAY_LEN (ssids); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay")); + for (i = 0; i < len; i++) { + const char *ssid = ssids[i]; + + g_variant_builder_add (&builder, + "@ay", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, ssid, strlen (ssid), 1)); + } + variant = g_variant_builder_end (&builder); + + if (nmtst_get_rand_bool ()) + g_variant_ref_sink (variant); + + ssids_arr = nmtst_ssids_options_to_ptrarray (variant, &error); + g_assert (!error); + if (len == 0) { + g_assert (!ssids_arr); + return; + } + g_assert_cmpint (len, ==, ssids_arr->len); + for (i = 0; i < len; i++) { + const char *ssid = ssids[i]; + GBytes *bytes = ssids_arr->pdata[i]; + + g_assert (nm_utils_gbytes_equal_mem (bytes, + ssid, + strlen (ssid))); + } +} + +static void +test_ssids_options_to_ptrarray (void) +{ + do_test_ssids_options_to_ptrarray (NM_PTRARRAY_EMPTY (const char *)); + do_test_ssids_options_to_ptrarray (NM_MAKE_STRV ("ab")); + do_test_ssids_options_to_ptrarray (NM_MAKE_STRV ("ab", "cd", "fsdfdsf")); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -1501,5 +1556,7 @@ main (int argc, char **argv) g_test_add_func ("/wifi/strength/all", test_strength_all); + g_test_add_func ("/wifi/ssids_options_to_ptrarray", test_ssids_options_to_ptrarray); + return g_test_run (); } |