diff options
Diffstat (limited to 'src/devices/wifi/nm-device-wifi.c')
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 782 |
1 files changed, 424 insertions, 358 deletions
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), |