From 3c19ce7616b15a7f577967912ef999e03a2b45d5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 5 Apr 2015 23:31:02 -0500 Subject: [PATCH 1/9] supplicant: track and expose wpa_supplicant's CurrentBSS property --- .../nm-supplicant-interface.c | 48 ++++++++++++++++--- .../nm-supplicant-interface.h | 6 +++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index 7f79964410..0a39ff9b51 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -64,6 +64,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0 = 0, PROP_SCANNING, + PROP_CURRENT_BSS, LAST_PROP }; @@ -91,6 +92,7 @@ typedef struct { char * net_path; guint32 blobs_left; GHashTable * bss_proxies; + char * current_bss; gint32 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_s() */ @@ -320,6 +322,17 @@ nm_supplicant_interface_get_scanning (NMSupplicantInterface *self) return FALSE; } +const char * +nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + return priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY ? priv->current_bss : NULL; +} + gint32 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self) { @@ -550,6 +563,8 @@ props_changed_cb (GDBusProxy *proxy, gint32 i32; GVariant *v; + g_object_freeze_notify (G_OBJECT (self)); + if (g_variant_lookup (changed_properties, "Scanning", "b", &b)) set_scanning (self, b); @@ -570,6 +585,16 @@ props_changed_cb (GDBusProxy *proxy, g_free (array); } + if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) { + if (strcmp (s, "/") == 0) + s = NULL; + if (g_strcmp0 (s, priv->current_bss) != 0) { + g_free (priv->current_bss); + priv->current_bss = g_strdup (s); + g_object_notify (G_OBJECT (self), NM_SUPPLICANT_INTERFACE_CURRENT_BSS); + } + } + v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT); if (v) { parse_capabilities (self, v); @@ -589,6 +614,8 @@ props_changed_cb (GDBusProxy *proxy, priv->disconnect_reason); } } + + g_object_thaw_notify (G_OBJECT (self)); } static void @@ -1268,11 +1295,7 @@ set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void @@ -1281,9 +1304,14 @@ get_property (GObject *object, GValue *value, GParamSpec *pspec) { + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object); + switch (prop_id) { case PROP_SCANNING: - g_value_set_boolean (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->scanning); + g_value_set_boolean (value, priv->scanning); + break; + case PROP_CURRENT_BSS: + g_value_set_string (value, priv->current_bss); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1314,6 +1342,7 @@ dispose (GObject *object) g_clear_pointer (&priv->net_path, g_free); g_clear_pointer (&priv->dev, g_free); g_clear_pointer (&priv->object_path, g_free); + g_clear_pointer (&priv->current_bss, g_free); g_clear_object (&priv->cfg); @@ -1340,6 +1369,13 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_CURRENT_BSS, + g_param_spec_string (NM_SUPPLICANT_INTERFACE_CURRENT_BSS, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /* Signals */ signals[STATE] = g_signal_new (NM_SUPPLICANT_INTERFACE_STATE, diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h index da3ad57048..6be89f4222 100644 --- a/src/supplicant-manager/nm-supplicant-interface.h +++ b/src/supplicant-manager/nm-supplicant-interface.h @@ -54,6 +54,10 @@ enum { #define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_INTERFACE)) #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass)) +/* Properties */ +#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" + +/* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" #define NM_SUPPLICANT_INTERFACE_REMOVED "removed" #define NM_SUPPLICANT_INTERFACE_NEW_BSS "new-bss" @@ -145,6 +149,8 @@ const char *nm_supplicant_interface_state_to_string (guint32 state); gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self); +const char *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self); + gint32 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self); const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self); From 6596ceee1442d37ea715be06f8a65195082db627 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 11:00:20 -0500 Subject: [PATCH 2/9] supplicant: ignore NotConnected errors when disconnecting --- src/supplicant-manager/nm-supplicant-interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index 0a39ff9b51..9c044308b1 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -888,8 +888,10 @@ log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) gs_free_error GError *error = NULL; reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (!reply && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", error->message, (char *) user_data); + if ( !reply + && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) + && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) + nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", (char *) user_data, error->message); } void From 6b8df2035ecb6c839c5db97ac7d03e175031f169 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 00:07:10 -0500 Subject: [PATCH 3/9] wifi: use a hash table to track access points --- src/devices/wifi/nm-device-wifi.c | 281 ++++++++++++++---------------- src/devices/wifi/nm-wifi-ap.c | 23 ++- src/devices/wifi/nm-wifi-ap.h | 6 +- 3 files changed, 154 insertions(+), 156 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 9c417f45b4..e46bcafa6e 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -116,14 +116,12 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _NMDeviceWifiPrivate { - gboolean disposed; - char * perm_hw_addr; /* Permanent MAC address */ char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ gint8 invalid_strength_counter; - GSList * ap_list; + GHashTable * aps; NMAccessPoint * current_ap; guint32 rate; gboolean enabled; /* rfkilled or not */ @@ -189,7 +187,10 @@ static void schedule_scanlist_cull (NMDeviceWifi *self); static gboolean request_wireless_scan (gpointer user_data); -static void remove_access_point (NMDeviceWifi *device, NMAccessPoint *ap); +static void emit_ap_added_removed (NMDeviceWifi *self, + guint signum, + NMAccessPoint *ap, + gboolean recheck_available_connections); static void remove_supplicant_interface_error_handler (NMDeviceWifi *self); @@ -315,31 +316,23 @@ supplicant_interface_release (NMDeviceWifi *self) static NMAccessPoint * get_ap_by_path (NMDeviceWifi *self, const char *path) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *iter; + g_return_val_if_fail (path != NULL, NULL); + return g_hash_table_lookup (NM_DEVICE_WIFI_GET_PRIVATE (self)->aps, path); - if (!path) - return NULL; - - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0) - return NM_AP (iter->data); - } - return NULL; } static NMAccessPoint * get_ap_by_supplicant_path (NMDeviceWifi *self, const char *path) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *iter; + GHashTableIter iter; + NMAccessPoint *ap; - if (!path) - return NULL; + g_return_val_if_fail (path != NULL, NULL); - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (path, nm_ap_get_supplicant_path (NM_AP (iter->data))) == 0) - return NM_AP (iter->data); + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (g_strcmp0 (path, nm_ap_get_supplicant_path (ap)) == 0) + return ap; } return NULL; } @@ -353,7 +346,6 @@ find_active_ap (NMDeviceWifi *self, int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); guint8 bssid[ETH_ALEN]; GByteArray *ssid; - GSList *iter; int i = 0; NMAccessPoint *match_nofreq = NULL, *active_ap = NULL; gboolean found_a_band = FALSE; @@ -382,11 +374,14 @@ find_active_ap (NMDeviceWifi *self, * and therefore it won't get matched the first time around. */ while (i++ < (match_hidden ? 2 : 1)) { + GHashTableIter iter; + NMAccessPoint *ap; + _LOGT (LOGD_WIFI, " Pass #%d %s", i, i > 1 ? "(ignoring SSID)" : ""); /* Find this SSID + BSSID in the device's AP list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint *ap = NM_AP (iter->data); + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { const char *ap_bssid = nm_ap_get_address (ap); const GByteArray *ap_ssid = nm_ap_get_ssid (ap); NM80211Mode apmode; @@ -521,13 +516,6 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai if (new_ap) { priv->current_ap = g_object_ref (new_ap); - /* Move the current AP to the front of the scan list. Since we - * do a lot of searches looking for the current AP, it saves - * time to have it in front. - */ - priv->ap_list = g_slist_remove (priv->ap_list, new_ap); - priv->ap_list = g_slist_prepend (priv->ap_list, new_ap); - /* Update seen BSSIDs cache */ update_seen_bssids_cache (self, priv->current_ap); } else @@ -537,7 +525,8 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai NM80211Mode mode = nm_ap_get_mode (old_ap); if (force_remove_old_ap || mode == NM_802_11_MODE_ADHOC || mode == NM_802_11_MODE_AP || nm_ap_get_fake (old_ap)) { - remove_access_point (self, old_ap); + emit_ap_added_removed (self, ACCESS_POINT_REMOVED, old_ap, FALSE); + g_hash_table_remove (priv->aps, nm_ap_get_dbus_path (old_ap)); if (recheck_available_connections) nm_device_recheck_available_connections (NM_DEVICE (self)); } @@ -674,33 +663,21 @@ emit_ap_added_removed (NMDeviceWifi *self, nm_device_recheck_available_connections (NM_DEVICE (self)); } -static void -remove_access_point (NMDeviceWifi *device, - NMAccessPoint *ap) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - g_return_if_fail (ap); - g_return_if_fail (ap != priv->current_ap); - g_return_if_fail (g_slist_find (priv->ap_list, ap)); - - priv->ap_list = g_slist_remove (priv->ap_list, ap); - emit_ap_added_removed (self, ACCESS_POINT_REMOVED, ap, FALSE); - g_object_unref (ap); -} - static void remove_all_aps (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GHashTableIter iter; + NMAccessPoint *ap; - if (priv->ap_list) { + if (g_hash_table_size (priv->aps)) { set_current_ap (self, NULL, FALSE, FALSE); - while (priv->ap_list) - remove_access_point (self, NM_AP (priv->ap_list->data)); - + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + emit_ap_added_removed (self, ACCESS_POINT_REMOVED, ap, FALSE); + g_hash_table_iter_remove (&iter); + } nm_device_recheck_available_connections (NM_DEVICE (self)); } } @@ -862,6 +839,28 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return TRUE; } +static NMAccessPoint * +find_first_compatible_ap (NMDeviceWifi *self, + NMConnection *connection, + gboolean allow_unstable_order) +{ + GHashTableIter iter; + NMAccessPoint *ap; + NMAccessPoint *cand_ap = NULL; + + g_return_val_if_fail (connection != NULL, NULL); + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (!nm_ap_check_compatible (ap, connection)) + continue; + if (allow_unstable_order) + return ap; + if (!cand_ap || (nm_ap_get_id (cand_ap) < nm_ap_get_id (ap))) + cand_ap = ap; + } + return cand_ap; +} static gboolean check_connection_available (NMDevice *device, @@ -869,10 +868,8 @@ check_connection_available (NMDevice *device, NMDeviceCheckConAvailableFlags flags, const char *specific_object) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); NMSettingWireless *s_wifi; const char *mode; - GSList *ap_iter = NULL; s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); @@ -906,13 +903,8 @@ check_connection_available (NMDevice *device, if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* check if its visible */ - for (ap_iter = priv->ap_list; ap_iter; ap_iter = g_slist_next (ap_iter)) { - if (nm_ap_check_compatible (NM_AP (ap_iter->data), connection)) - return TRUE; - } - - return FALSE; + /* check at least one AP is compatible with this connection */ + return !!find_first_compatible_ap (NM_DEVICE_WIFI (device), connection, TRUE); } /* @@ -969,7 +961,6 @@ complete_connection (NMDevice *device, const GByteArray *ssid = NULL; GByteArray *tmp_ssid = NULL; GBytes *setting_ssid = NULL; - GSList *iter; gboolean hidden = FALSE; s_wifi = nm_connection_get_setting_wireless (connection); @@ -996,12 +987,7 @@ complete_connection (NMDevice *device, } /* Find a compatible AP in the scan list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (nm_ap_check_compatible (NM_AP (iter->data), connection)) { - ap = NM_AP (iter->data); - break; - } - } + ap = find_first_compatible_ap (self, connection, FALSE); /* If we still don't have an AP, then the WiFI settings needs to be * fully specified by the client. Might not be able to find an AP @@ -1162,8 +1148,7 @@ can_auto_connect (NMDevice *device, char **specific_object) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *ap_iter; + NMAccessPoint *ap; const char *method = NULL; guint64 timestamp = 0; @@ -1184,33 +1169,53 @@ can_auto_connect (NMDevice *device, if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) return TRUE; - for (ap_iter = priv->ap_list; ap_iter; ap_iter = g_slist_next (ap_iter)) { - NMAccessPoint *ap = NM_AP (ap_iter->data); - - if (nm_ap_check_compatible (ap, connection)) { - /* All good; connection is usable */ - *specific_object = (char *) nm_ap_get_dbus_path (ap); - return TRUE; - } + ap = find_first_compatible_ap (self, connection, FALSE); + if (ap) { + /* All good; connection is usable */ + *specific_object = (char *) nm_ap_get_dbus_path (ap); + return TRUE; } return FALSE; } +static gint +ap_id_compare (NMAccessPoint *a, NMAccessPoint *b) +{ + guint32 a_id = nm_ap_get_id (a); + guint32 b_id = nm_ap_get_id (b); + + return a_id < b_id ? -1 : (a_id == b_id ? 0 : 1); +} + +static GSList * +get_sorted_ap_list (NMDeviceWifi *self) +{ + GSList *sorted = NULL; + GHashTableIter iter; + NMAccessPoint *ap; + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) + sorted = g_slist_prepend (sorted, ap); + return g_slist_sort (sorted, (GCompareFunc) ap_id_compare); +} + static void ap_list_dump (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList * elt; - int i = 0; + GSList *sorted, *iter; g_return_if_fail (NM_IS_DEVICE_WIFI (self)); + if (!nm_logging_enabled (LOGL_DEBUG, LOGD_WIFI_SCAN)) + return; + _LOGD (LOGD_WIFI_SCAN, "Current AP list:"); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt), i++) { - NMAccessPoint * ap = NM_AP (elt->data); - nm_ap_dump (ap, "List AP: "); - } + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) + nm_ap_dump (NM_AP (iter->data), "List AP: "); + g_slist_free (sorted); _LOGD (LOGD_WIFI_SCAN, "Current AP list: done"); } @@ -1219,16 +1224,17 @@ impl_device_get_access_points (NMDeviceWifi *self, GPtrArray **aps, GError **err) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *elt; + GSList *sorted, *iter; *aps = g_ptr_array_new (); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *ap = NM_AP (elt->data); + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) { + NMAccessPoint *ap = NM_AP (iter->data); if (nm_ap_get_ssid (ap)) g_ptr_array_add (*aps, g_strdup (nm_ap_get_dbus_path (ap))); } + g_slist_free (sorted); return TRUE; } @@ -1237,12 +1243,13 @@ impl_device_get_all_access_points (NMDeviceWifi *self, GPtrArray **aps, GError **err) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *elt; + GSList *sorted, *iter; *aps = g_ptr_array_new (); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) - g_ptr_array_add (*aps, g_strdup (nm_ap_get_dbus_path (NM_AP (elt->data)))); + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) + g_ptr_array_add (*aps, g_strdup (nm_ap_get_dbus_path (NM_AP (iter->data)))); + g_slist_free (sorted); return TRUE; } @@ -1710,7 +1717,7 @@ merge_scanned_ap (NMDeviceWifi *self, found_ap = get_ap_by_supplicant_path (self, nm_ap_get_supplicant_path (merge_ap)); if (!found_ap) - found_ap = nm_ap_match_in_list (merge_ap, priv->ap_list, strict_match); + found_ap = nm_ap_match_in_hash (merge_ap, priv->aps, strict_match); if (found_ap) { _LOGD (LOGD_WIFI_SCAN, "merging AP '%s' %s (%p) with existing (%p)", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", @@ -1740,8 +1747,8 @@ merge_scanned_ap (NMDeviceWifi *self, str_if_set (bssid, "(none)"), merge_ap); g_object_ref (merge_ap); - priv->ap_list = g_slist_prepend (priv->ap_list, merge_ap); nm_ap_export_to_dbus (merge_ap); + g_hash_table_insert (priv->aps, (gpointer) nm_ap_get_dbus_path (merge_ap), merge_ap); emit_ap_added_removed (self, ACCESS_POINT_ADDED, merge_ap, TRUE); } } @@ -1751,9 +1758,9 @@ cull_scan_list (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); gint32 now = nm_utils_get_monotonic_timestamp_s (); - GSList *outdated_list = NULL; - GSList *elt; guint32 removed = 0, total = 0; + GHashTableIter iter; + NMAccessPoint *ap; priv->scanlist_cull_id = 0; @@ -1762,8 +1769,8 @@ cull_scan_list (NMDeviceWifi *self) /* Walk the access point list and remove any access points older than * three times the inactive scan interval. */ - for (elt = priv->ap_list; elt; elt = g_slist_next (elt), total++) { - NMAccessPoint *ap = elt->data; + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { const guint prune_interval_s = SCAN_INTERVAL_MAX * 3; gint32 last_seen; @@ -1784,28 +1791,21 @@ cull_scan_list (NMDeviceWifi *self) continue; last_seen = nm_ap_get_last_seen (ap); - if (!last_seen || last_seen + prune_interval_s < now) - outdated_list = g_slist_prepend (outdated_list, ap); + if (!last_seen || last_seen + prune_interval_s < now) { + const GByteArray *ssid = nm_ap_get_ssid (ap); + + _LOGD (LOGD_WIFI_SCAN, + " removing %s (%s%s%s)", + str_if_set (nm_ap_get_address (ap), "(none)"), + ssid ? "'" : "", + ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", + ssid ? "'" : ""); + emit_ap_added_removed (self, ACCESS_POINT_REMOVED, ap, FALSE); + g_hash_table_iter_remove (&iter); + removed++; + } } - /* Remove outdated APs */ - for (elt = outdated_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *outdated_ap = NM_AP (elt->data); - const GByteArray *ssid; - - ssid = nm_ap_get_ssid (outdated_ap); - _LOGD (LOGD_WIFI_SCAN, - " removing %s (%s%s%s)", - str_if_set (nm_ap_get_address (outdated_ap), "(none)"), - ssid ? "'" : "", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - ssid ? "'" : ""); - - remove_access_point (self, outdated_ap); - removed++; - } - g_slist_free (outdated_list); - _LOGD (LOGD_WIFI_SCAN, "removed %d APs (of %d)", removed, total); @@ -2573,7 +2573,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) NMConnection *connection; NMSettingWireless *s_wireless; const char *cloned_mac; - GSList *iter; const char *mode; const char *ap_path; @@ -2620,21 +2619,12 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) /* AP mode never uses a specific object or existing scanned AP */ if (priv->mode != NM_802_11_MODE_AP) { - ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); ap = ap_path ? get_ap_by_path (self, ap_path) : NULL; if (ap) goto done; - /* Find a compatible AP in the scan list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint *candidate = NM_AP (iter->data); - - if (nm_ap_check_compatible (candidate, connection)) { - ap = candidate; - break; - } - } + ap = find_first_compatible_ap (self, connection, FALSE); } if (ap) { @@ -2656,8 +2646,8 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) else if (nm_ap_is_hotspot (ap)) nm_ap_set_address (ap, nm_device_get_hw_address (device)); - priv->ap_list = g_slist_prepend (priv->ap_list, ap); nm_ap_export_to_dbus (ap); + g_hash_table_insert (priv->aps, (gpointer) nm_ap_get_dbus_path (ap), ap); g_object_freeze_notify (G_OBJECT (self)); set_current_ap (self, ap, FALSE, FALSE); emit_ap_added_removed (self, ACCESS_POINT_ADDED, ap, TRUE); @@ -3223,7 +3213,10 @@ nm_device_wifi_new (NMPlatformLink *platform_device) static void nm_device_wifi_init (NMDeviceWifi *self) { - NM_DEVICE_WIFI_GET_PRIVATE (self)->mode = NM_802_11_MODE_INFRA; + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + priv->mode = NM_802_11_MODE_INFRA; + priv->aps = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); } static void @@ -3232,13 +3225,6 @@ dispose (GObject *object) NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (priv->disposed) { - G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - if (priv->periodic_source_id) { g_source_remove (priv->periodic_source_id); priv->periodic_source_id = 0; @@ -3262,6 +3248,7 @@ finalize (GObject *object) g_free (priv->perm_hw_addr); g_free (priv->initial_hw_addr); + g_clear_pointer (&priv->aps, g_hash_table_unref); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3272,8 +3259,9 @@ get_property (GObject *object, guint prop_id, { NMDeviceWifi *device = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); + GHashTableIter iter; + const char *dbus_path; GPtrArray *array; - GSList *iter; switch (prop_id) { case PROP_PERM_HW_ADDRESS: @@ -3289,9 +3277,10 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->capabilities); break; case PROP_ACCESS_POINTS: - array = g_ptr_array_sized_new (4); - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) - g_ptr_array_add (array, g_strdup (nm_ap_get_dbus_path (NM_AP (iter->data)))); + array = g_ptr_array_sized_new (g_hash_table_size (priv->aps)); + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, (gpointer) &dbus_path, NULL)) + g_ptr_array_add (array, g_strdup (dbus_path)); g_value_take_boxed (value, array); break; case PROP_ACTIVE_ACCESS_POINT: @@ -3313,11 +3302,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index c0f8b11dff..3ebf3a5a2d 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -44,6 +44,7 @@ typedef struct { char *dbus_path; char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ + guint32 id; /* ID for stable sorting of APs */ /* Scanned or cached values */ GByteArray * ssid; @@ -314,7 +315,8 @@ nm_ap_export_to_dbus (NMAccessPoint *ap) return; } - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH_ACCESS_POINT "/%d", counter++); + priv->id = counter++; + priv->dbus_path = g_strdup_printf (NM_DBUS_PATH_ACCESS_POINT "/%d", priv->id); nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, ap); } @@ -723,6 +725,14 @@ nm_ap_get_supplicant_path (NMAccessPoint *ap) return NM_AP_GET_PRIVATE (ap)->supplicant_path; } +guint32 +nm_ap_get_id (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), 0); + + return NM_AP_GET_PRIVATE (ap)->id; +} + void nm_ap_set_supplicant_path (NMAccessPoint *ap, const char *path) { @@ -1186,16 +1196,17 @@ capabilities_compatible (NM80211ApSecurityFlags a_flags, NM80211ApSecurityFlags } NMAccessPoint * -nm_ap_match_in_list (NMAccessPoint *find_ap, - GSList *ap_list, +nm_ap_match_in_hash (NMAccessPoint *find_ap, + GHashTable *hash, gboolean strict_match) { - GSList *iter; + GHashTableIter iter; + NMAccessPoint *list_ap; g_return_val_if_fail (find_ap != NULL, NULL); - for (iter = ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint * list_ap = NM_AP (iter->data); + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &list_ap)) { const GByteArray * list_ssid = nm_ap_get_ssid (list_ap); const char * list_addr = nm_ap_get_address (list_ap); diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 8ad9acb71b..0b896f6677 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -66,6 +66,8 @@ const char *nm_ap_get_supplicant_path (NMAccessPoint *ap); void nm_ap_set_supplicant_path (NMAccessPoint *ap, const char *path); +guint32 nm_ap_get_id (NMAccessPoint *ap); + const GByteArray *nm_ap_get_ssid (const NMAccessPoint * ap); void nm_ap_set_ssid (NMAccessPoint * ap, const guint8 * ssid, gsize len); @@ -112,8 +114,8 @@ gboolean nm_ap_complete_connection (NMAccessPoint *self, gboolean lock_bssid, GError **error); -NMAccessPoint * nm_ap_match_in_list (NMAccessPoint *find_ap, - GSList *ap_list, +NMAccessPoint * nm_ap_match_in_hash (NMAccessPoint *find_ap, + GHashTable *hash, gboolean strict_match); void nm_ap_dump (NMAccessPoint *ap, const char *prefix); From 37760fdc8341843e18ff13f01a8814a26c731e89 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 09:41:04 -0500 Subject: [PATCH 4/9] wifi: use supplicant's CurrentBSS as the current AP Instead of keeping track of it internally, and attempting to fuzzy-match access points and stuff, just use the supplicant's information. If the supplicant doesn't know what AP it's talking to, then we've got more problems than just NM code. The theory here is that when starting activation, we'll use the given access point from the scan list that the supplicant already knows about. If there isn't one yet (adhoc, hidden, or AP mode) then we'll create a fake AP and add it to the scan list. Once the supplicant has associated to the AP, it'll notify about the current BSS which we then look up in the scan list, and set priv->current AP to that. If for some reason the given AP isn't yet in our scan list (which often happens for adhoc/AP) then we'll just live with the fake AP until we get the scan result, which should happen very soon. We don't need to do any fuzzy-matching to find the current AP because it will either always be one the supplicant knows about, or a fake one that the supplicant doesn't know about that will be replaced soon anyway. --- src/devices/wifi/nm-device-wifi.c | 345 ++++++++---------------------- 1 file changed, 95 insertions(+), 250 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index e46bcafa6e..c14749a8ab 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -42,6 +42,7 @@ #include "nm-device-private.h" #include "nm-utils.h" #include "nm-logging.h" +#include "gsystem-local-alloc.h" #include "NetworkManagerUtils.h" #include "nm-activation-request.h" #include "nm-supplicant-manager.h" @@ -183,6 +184,10 @@ 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); + static void schedule_scanlist_cull (NMDeviceWifi *self); static gboolean request_wireless_scan (gpointer user_data); @@ -274,6 +279,10 @@ supplicant_interface_acquire (NMDeviceWifi *self) "notify::scanning", G_CALLBACK (supplicant_iface_notify_scanning_cb), self); + g_signal_connect (priv->sup_iface, + "notify::" NM_SUPPLICANT_INTERFACE_CURRENT_BSS, + G_CALLBACK (supplicant_iface_notify_current_bss), + self); return TRUE; } @@ -337,145 +346,6 @@ get_ap_by_supplicant_path (NMDeviceWifi *self, const char *path) return NULL; } -static NMAccessPoint * -find_active_ap (NMDeviceWifi *self, - NMAccessPoint *ignore_ap, - gboolean match_hidden) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - guint8 bssid[ETH_ALEN]; - GByteArray *ssid; - int i = 0; - NMAccessPoint *match_nofreq = NULL, *active_ap = NULL; - gboolean found_a_band = FALSE; - gboolean found_bg_band = FALSE; - NM80211Mode devmode; - guint32 devfreq; - - nm_platform_wifi_get_bssid (ifindex, bssid); - _LOGT (LOGD_WIFI, "active BSSID: %02x:%02x:%02x:%02x:%02x:%02x", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - - if (!nm_ethernet_address_is_valid (bssid, ETH_ALEN)) - return NULL; - - ssid = nm_platform_wifi_get_ssid (ifindex); - _LOGT (LOGD_WIFI, "active SSID: %s%s%s", - ssid ? "'" : "", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - ssid ? "'" : ""); - - devmode = nm_platform_wifi_get_mode (ifindex); - devfreq = nm_platform_wifi_get_frequency (ifindex); - - /* When matching hidden APs, do a second pass that ignores the SSID check, - * because NM might not yet know the SSID of the hidden AP in the scan list - * and therefore it won't get matched the first time around. - */ - while (i++ < (match_hidden ? 2 : 1)) { - GHashTableIter iter; - NMAccessPoint *ap; - - _LOGT (LOGD_WIFI, " Pass #%d %s", i, i > 1 ? "(ignoring SSID)" : ""); - - /* Find this SSID + BSSID in the device's AP list */ - g_hash_table_iter_init (&iter, priv->aps); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { - const char *ap_bssid = nm_ap_get_address (ap); - const GByteArray *ap_ssid = nm_ap_get_ssid (ap); - NM80211Mode apmode; - guint32 apfreq; - - _LOGT (LOGD_WIFI, " AP: %s%s%s %s", - ap_ssid ? "'" : "", - ap_ssid ? nm_utils_escape_ssid (ap_ssid->data, ap_ssid->len) : "(none)", - ap_ssid ? "'" : "", - str_if_set (ap_bssid, "(none)")); - - if (ap == ignore_ap) { - _LOGT (LOGD_WIFI, " ignored"); - continue; - } - - if (!nm_utils_hwaddr_matches (bssid, ETH_ALEN, ap_bssid, -1)) { - _LOGT (LOGD_WIFI, " BSSID mismatch"); - continue; - } - - if (i == 0) { - if ( (ssid && !ap_ssid) - || (ap_ssid && !ssid) - || (ssid && ap_ssid && !nm_utils_same_ssid (ssid->data, ssid->len, - ap_ssid->data, ap_ssid->len, - TRUE))) { - _LOGT (LOGD_WIFI, " SSID mismatch"); - continue; - } - } - - apmode = nm_ap_get_mode (ap); - if (devmode != apmode) { - _LOGT (LOGD_WIFI, " mode mismatch (device %d, ap %d)", - devmode, apmode); - continue; - } - - apfreq = nm_ap_get_freq (ap); - if (devfreq != apfreq) { - _LOGT (LOGD_WIFI, " frequency mismatch (device %u, ap %u)", - devfreq, apfreq); - - if (match_nofreq == NULL) - match_nofreq = ap; - - if (apfreq > 4000) - found_a_band = TRUE; - else if (apfreq > 2000) - found_bg_band = TRUE; - continue; - } - - // FIXME: handle security settings here too - _LOGT (LOGD_WIFI, " matched"); - active_ap = ap; - goto done; - } - } - - /* Some proprietary drivers (wl.o) report tuned frequency (like when - * scanning) instead of the associated AP's frequency. This is a great - * example of how WEXT is underspecified. We use frequency to find the - * active AP in the scan list because some configurations use the same - * SSID/BSSID on the 2GHz and 5GHz bands simultaneously, and we need to - * make sure we get the right AP in the right band. This configuration - * is uncommon though, and the frequency check penalizes closed drivers we - * can't fix. Because we're not total dicks, ignore the frequency condition - * if the associated BSSID/SSID exists only in one band since that's most - * likely the AP we want. Sometimes wl.o returns a frequency of 0, so if - * we can't match the AP based on frequency at all, just give up. - */ - if (match_nofreq && ((found_a_band != found_bg_band) || (devfreq == 0))) { - const GByteArray *ap_ssid = nm_ap_get_ssid (match_nofreq); - - _LOGT (LOGD_WIFI, " matched %s%s%s %s", - ap_ssid ? "'" : "", - ap_ssid ? nm_utils_escape_ssid (ap_ssid->data, ap_ssid->len) : "(none)", - ap_ssid ? "'" : "", - str_if_set (nm_ap_get_address (match_nofreq), "(none)")); - - active_ap = match_nofreq; - goto done; - } - - _LOGT (LOGD_WIFI, " No matching AP found."); - -done: - if (ssid) - g_byte_array_free (ssid, TRUE); - return active_ap; -} - static void update_seen_bssids_cache (NMDeviceWifi *self, NMAccessPoint *ap) { @@ -537,11 +407,10 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai } static void -periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) +periodic_update (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - NMAccessPoint *new_ap; guint32 new_rate; int percent; NMDeviceState state; @@ -568,65 +437,15 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) if (priv->mode == NM_802_11_MODE_AP) return; - /* In IBSS mode, most newer firmware/drivers do "BSS coalescing" where - * multiple IBSS stations using the same SSID will eventually switch to - * using the same BSSID to avoid network segmentation. When this happens, - * the card's reported BSSID will change, but the new BSS may not - * be in the scan list, since scanning isn't done in ad-hoc mode for - * various reasons. So pull the BSSID from the card and update the - * current AP with it, if the current AP is adhoc. - */ - if (priv->current_ap && (nm_ap_get_mode (priv->current_ap) == NM_802_11_MODE_ADHOC)) { - guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; - - nm_platform_wifi_get_bssid (ifindex, bssid); - /* 0x02 means "locally administered" and should be OR-ed into - * the first byte of IBSS BSSIDs. - */ - if ((bssid[0] & 0x02) && nm_ethernet_address_is_valid (bssid, ETH_ALEN)) { - char *bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); - nm_ap_set_address (priv->current_ap, bssid_str); - g_free (bssid_str); - } - } - - new_ap = find_active_ap (self, ignore_ap, FALSE); - if (new_ap) { - /* Try to smooth out the strength. Atmel cards, for example, will give no strength - * one second and normal strength the next. - */ + if (priv->current_ap) { + /* Smooth out the strength to work around crappy drivers */ percent = nm_platform_wifi_get_quality (ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { - nm_ap_set_strength (new_ap, (gint8) percent); + nm_ap_set_strength (priv->current_ap, (gint8) percent); priv->invalid_strength_counter = 0; } } - if (new_ap != priv->current_ap) { - const char *new_bssid = NULL; - const GByteArray *new_ssid = NULL; - const char *old_bssid = NULL; - const GByteArray *old_ssid = NULL; - - if (new_ap) { - new_bssid = nm_ap_get_address (new_ap); - new_ssid = nm_ap_get_ssid (new_ap); - } - - if (priv->current_ap) { - old_bssid = nm_ap_get_address (priv->current_ap); - old_ssid = nm_ap_get_ssid (priv->current_ap); - } - - _LOGI (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", - old_bssid ? old_bssid : "(none)", - old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", - new_bssid ? new_bssid : "(none)", - new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); - - set_current_ap (self, new_ap, TRUE, FALSE); - } - new_rate = nm_platform_wifi_get_rate (ifindex); if (new_rate != priv->rate) { priv->rate = new_rate; @@ -637,7 +456,7 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) static gboolean periodic_update_cb (gpointer user_data) { - periodic_update (NM_DEVICE_WIFI (user_data), NULL); + periodic_update (NM_DEVICE_WIFI (user_data)); return TRUE; } @@ -1834,6 +1653,7 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, GVariant *properties, NMDeviceWifi *self) { + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDeviceState state; NMAccessPoint *ap; @@ -1855,6 +1675,12 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, /* Add the AP to the device's AP list */ merge_scanned_ap (self, ap); g_object_unref (ap); + + /* 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) + supplicant_iface_notify_current_bss (priv->sup_iface, NULL, self); } else _LOGW (LOGD_WIFI_SCAN, "invalid AP properties received"); @@ -2215,7 +2041,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, g_bytes_get_size (ssid)) : "(none)"); nm_device_activate_schedule_stage3_ip_config_start (device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self, NULL); + periodic_update (self); break; case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { @@ -2315,7 +2141,53 @@ supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, /* Run a quick update of current AP when coming out of a scan */ state = nm_device_get_state (NM_DEVICE (self)); if (!scanning && state == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self, NULL); + 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; + NMAccessPoint *new_ap = NULL; + + current_bss = nm_supplicant_interface_get_current_bss (iface); + if (current_bss) + new_ap = get_ap_by_supplicant_path (self, current_bss); + + if (new_ap != priv->current_ap) { + const char *new_bssid = NULL; + const GByteArray *new_ssid = NULL; + const char *old_bssid = NULL; + const GByteArray *old_ssid = NULL; + + /* Don't ever replace a "fake" current AP if we don't know about the + * supplicant's current BSS yet. It'll get replaced when we receive + * the current BSS's scan result. + */ + if (new_ap == NULL && nm_ap_get_fake (priv->current_ap)) + return; + + if (new_ap) { + new_bssid = nm_ap_get_address (new_ap); + new_ssid = nm_ap_get_ssid (new_ap); + } + + if (priv->current_ap) { + old_bssid = nm_ap_get_address (priv->current_ap); + old_ssid = nm_ap_get_ssid (priv->current_ap); + } + + _LOGD (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", + old_bssid ? old_bssid : "(none)", + old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", + new_bssid ? new_bssid : "(none)", + new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); + + set_current_ap (self, new_ap, TRUE, FALSE); + } } static NMActStageReturn @@ -2979,9 +2851,6 @@ activation_success_handler (NMDevice *device) NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (device); - NMAccessPoint *ap; - guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; - NMAccessPoint *tmp_ap = NULL; NMActRequest *req; NMConnection *connection; @@ -2997,62 +2866,38 @@ activation_success_handler (NMDevice *device) /* Clear wireless secrets tries on success */ g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); - ap = priv->current_ap; - - /* If the AP isn't fake, it was found in the scan list and all its - * details are known. + /* There should always be a current AP, either a fake one because we haven't + * seen a scan result for the activated AP yet, or a real one from the + * supplicant's scan list. */ - if (!ap || !nm_ap_get_fake (ap)){ - ap = NULL; - goto done; - } + g_warn_if_fail (priv->current_ap); + if (priv->current_ap) { + if (nm_ap_get_fake (priv->current_ap)) { + /* If the activation AP hasn't been seen by the supplicant in a scan + * yet, it will be "fake". This usually happens for Ad-Hoc and + * AP-mode connections. Fill in the details from the device itself + * until the supplicant sends the scan result. + */ + if (!nm_ap_get_address (priv->current_ap)) { + guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + gs_free char *bssid_str = NULL; - /* If the activate AP was fake, it probably won't have a BSSID at all. - * But if activation was successful, the card will know the BSSID. Grab - * the BSSID off the card and fill in the BSSID of the activation AP. - */ - nm_platform_wifi_get_bssid (ifindex, bssid); - if (!nm_ap_get_address (ap)) { - char *bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); - nm_ap_set_address (ap, bssid_str); - g_free (bssid_str); - } - if (!nm_ap_get_freq (ap)) - nm_ap_set_freq (ap, nm_platform_wifi_get_frequency (ifindex)); - if (!nm_ap_get_max_bitrate (ap)) - nm_ap_set_max_bitrate (ap, nm_platform_wifi_get_rate (ifindex)); - - tmp_ap = find_active_ap (self, ap, TRUE); - if (tmp_ap) { - const GByteArray *ssid = nm_ap_get_ssid (tmp_ap); - - /* Found a better match in the scan list than the fake AP. Use it - * instead. - */ - - /* If the better match was a hidden AP, update its SSID */ - if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { - ssid = nm_ap_get_ssid (ap); - nm_ap_set_ssid (tmp_ap, ssid->data, ssid->len); + if ( nm_platform_wifi_get_bssid (ifindex, bssid) + && nm_ethernet_address_is_valid (bssid, ETH_ALEN)) { + bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); + nm_ap_set_address (priv->current_ap, bssid_str); + } + } + if (!nm_ap_get_freq (priv->current_ap)) + nm_ap_set_freq (priv->current_ap, nm_platform_wifi_get_frequency (ifindex)); + if (!nm_ap_get_max_bitrate (priv->current_ap)) + nm_ap_set_max_bitrate (priv->current_ap, nm_platform_wifi_get_rate (ifindex)); } - nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_ap_get_dbus_path (tmp_ap)); + nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), nm_ap_get_dbus_path (priv->current_ap)); } -done: - periodic_update (self, ap); - - /* ap might be already unrefed, because it was a fake_ap. But we don't touch it... */ - if (tmp_ap && ap == priv->current_ap) { - /* Strange, we would expect periodic_update() to find a better AP - * then the fake one and reset it. Reset the fake current_ap to NULL - * now, which will remove the fake ap. - **/ - set_current_ap (self, NULL, TRUE, FALSE); - } - - /* No need to update seen BSSIDs cache, that is done by set_current_ap() already */ + periodic_update (self); /* Reset scan interval to something reasonable */ priv->scan_interval = SCAN_INTERVAL_MIN + (SCAN_INTERVAL_STEP * 2); From 0bdee17402057a8fc0e054de828113208bd76b5b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 11:36:34 -0500 Subject: [PATCH 5/9] wifi: update AP properties from supplicant signals --- src/devices/wifi/nm-device-wifi.c | 2 +- src/devices/wifi/nm-wifi-ap.c | 48 ++++++++++++++++++++----------- src/devices/wifi/nm-wifi-ap.h | 4 +++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index c14749a8ab..87c1abfa29 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1709,7 +1709,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, /* Update the AP's last-seen property */ ap = get_ap_by_supplicant_path (self, object_path); if (ap) - nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); + nm_ap_update_from_properties (ap, object_path, properties); /* Remove outdated access points */ schedule_scanlist_cull (self); diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 3ebf3a5a2d..ae318b0197 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -34,6 +34,7 @@ #include "nm-setting-wireless.h" #include "nm-glib-compat.h" +#include "gsystem-local-alloc.h" #include "nm-access-point-glue.h" @@ -370,14 +371,13 @@ security_from_vardict (GVariant *security) return flags; } -NMAccessPoint * -nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +void +nm_ap_update_from_properties (NMAccessPoint *ap, + const char *supplicant_path, + GVariant *properties) { - const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; const char *addr; const guint8 *bytes; - NMAccessPoint *ap; GVariant *v; gsize len; gboolean b = FALSE; @@ -385,9 +385,8 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) gint16 i16; guint16 u16; - g_return_val_if_fail (properties != NULL, NULL); - - ap = nm_ap_new (); + g_return_if_fail (ap != NULL); + g_return_if_fail (properties != NULL); g_object_freeze_notify (G_OBJECT (ap)); @@ -421,6 +420,9 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) g_variant_unref (v); } + if (!nm_ap_get_ssid (ap)) + nm_ap_set_broadcast (ap, FALSE); + v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); if (v) { bytes = g_variant_get_fixed_array (v, &len, 1); @@ -459,7 +461,28 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) g_variant_unref (v); } - nm_ap_set_supplicant_path (ap, supplicant_path); + if (!nm_ap_get_supplicant_path (ap)) + nm_ap_set_supplicant_path (ap, supplicant_path); + + nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); + + g_object_thaw_notify (G_OBJECT (ap)); +} + +NMAccessPoint * +nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +{ + const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + NMAccessPoint *ap; + const char *addr; + + g_return_val_if_fail (supplicant_path != NULL, NULL); + g_return_val_if_fail (properties != NULL, NULL); + + ap = nm_ap_new (); + + nm_ap_update_from_properties (ap, supplicant_path, properties); /* ignore APs with invalid BSSIDs */ addr = nm_ap_get_address (ap); @@ -469,13 +492,6 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) return NULL; } - nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); - - if (!nm_ap_get_ssid (ap)) - nm_ap_set_broadcast (ap, FALSE); - - g_object_thaw_notify (G_OBJECT (ap)); - return ap; } diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 0b896f6677..01a104d669 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -60,6 +60,10 @@ NMAccessPoint * nm_ap_new_from_properties (const char *supplicant_path, NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection); void nm_ap_export_to_dbus (NMAccessPoint *ap); +void nm_ap_update_from_properties (NMAccessPoint *ap, + const char *supplicant_path, + GVariant *properties); + const char *nm_ap_get_dbus_path (NMAccessPoint *ap); const char *nm_ap_get_supplicant_path (NMAccessPoint *ap); From f191e204ace3bb5ebcadd03e275e919561e6680a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 11:42:16 -0500 Subject: [PATCH 6/9] wifi: trivial whitespace fixup --- src/devices/wifi/nm-device-wifi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 87c1abfa29..c90f054409 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1741,7 +1741,7 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, */ nm_ap_set_last_seen (ap, MAX (last_seen, now - SCAN_INTERVAL_MAX)); g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE)); -} + } } static void From 85aac315c042914a333a99b841095318c1a81e7f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 12:58:47 -0500 Subject: [PATCH 7/9] wifi: always strict-match access points when merging The only reason to allow lazy matching was to update a fake current AP when its real scan result comes in. Now that NM tracks the current AP based on the the supplicant's current BSS, a fake current AP will be replaced when the real scan result arrives. So it's pointless to update the fake one when it'll just be removed soon. --- src/devices/wifi/nm-device-wifi.c | 46 +++++------------------------ src/devices/wifi/nm-wifi-ap.c | 48 ++++--------------------------- src/devices/wifi/nm-wifi-ap.h | 4 +-- 3 files changed, 14 insertions(+), 84 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index c90f054409..ae3c91bbd7 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1483,27 +1483,16 @@ try_fill_ssid_for_hidden_ap (NMAccessPoint *ap) } } -/* - * merge_scanned_ap - * - * If there is already an entry that matches the BSSID and ESSID of the - * AP to merge, replace that entry with the scanned AP. Otherwise, add - * the scanned AP to the list. - * - * TODO: possibly need to differentiate entries based on security too; i.e. if - * there are two scan results with the same BSSID and SSID but different - * security options? - * - */ static void merge_scanned_ap (NMDeviceWifi *self, - NMAccessPoint *merge_ap) + NMAccessPoint *merge_ap, + const char *supplicant_path, + GVariant *properties) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMAccessPoint *found_ap = NULL; const GByteArray *ssid; const char *bssid; - gboolean strict_match = TRUE; /* Let the manager try to fill in the SSID from seen-bssids lists */ bssid = nm_ap_get_address (merge_ap); @@ -1525,18 +1514,9 @@ merge_scanned_ap (NMDeviceWifi *self, } } - /* If the incoming scan result matches the hidden AP that NM is currently - * connected to but hasn't been seen in the scan list yet, don't use - * strict matching. Because the capabilities of the fake AP have to be - * constructed from the NMConnection of the activation request, they won't - * always be the same as the capabilities of the real AP from the scan. - */ - if (priv->current_ap && nm_ap_get_fake (priv->current_ap)) - strict_match = FALSE; - - found_ap = get_ap_by_supplicant_path (self, nm_ap_get_supplicant_path (merge_ap)); + found_ap = get_ap_by_supplicant_path (self, supplicant_path); if (!found_ap) - found_ap = nm_ap_match_in_hash (merge_ap, priv->aps, strict_match); + found_ap = nm_ap_match_in_hash (merge_ap, priv->aps); if (found_ap) { _LOGD (LOGD_WIFI_SCAN, "merging AP '%s' %s (%p) with existing (%p)", ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", @@ -1544,19 +1524,7 @@ merge_scanned_ap (NMDeviceWifi *self, merge_ap, found_ap); - nm_ap_set_supplicant_path (found_ap, nm_ap_get_supplicant_path (merge_ap)); - nm_ap_set_flags (found_ap, nm_ap_get_flags (merge_ap)); - nm_ap_set_wpa_flags (found_ap, nm_ap_get_wpa_flags (merge_ap)); - nm_ap_set_rsn_flags (found_ap, nm_ap_get_rsn_flags (merge_ap)); - nm_ap_set_strength (found_ap, nm_ap_get_strength (merge_ap)); - nm_ap_set_last_seen (found_ap, nm_ap_get_last_seen (merge_ap)); - nm_ap_set_broadcast (found_ap, nm_ap_get_broadcast (merge_ap)); - nm_ap_set_freq (found_ap, nm_ap_get_freq (merge_ap)); - nm_ap_set_max_bitrate (found_ap, nm_ap_get_max_bitrate (merge_ap)); - - /* If the AP is noticed in a scan, it's automatically no longer - * fake, since it clearly exists somewhere. - */ + nm_ap_update_from_properties (found_ap, supplicant_path, properties); nm_ap_set_fake (found_ap, FALSE); g_object_set_data (G_OBJECT (found_ap), WPAS_REMOVED_TAG, NULL); } else { @@ -1673,7 +1641,7 @@ supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, nm_ap_dump (ap, "New AP: "); /* Add the AP to the device's AP list */ - merge_scanned_ap (self, ap); + merge_scanned_ap (self, ap, object_path, properties); g_object_unref (ap); /* Update the current AP if the supplicant notified a current BSS change diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index ae318b0197..107cac77ed 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -1190,31 +1190,8 @@ nm_ap_complete_connection (NMAccessPoint *self, error); } -static gboolean -capabilities_compatible (NM80211ApSecurityFlags a_flags, NM80211ApSecurityFlags b_flags) -{ - if (a_flags == b_flags) - return TRUE; - - /* Make sure there's a common key management method */ - if (!((a_flags & 0x300) & (b_flags & 0x300))) - return FALSE; - - /* Ensure common pairwise ciphers */ - if (!((a_flags & 0xF) & (b_flags & 0xF))) - return FALSE; - - /* Ensure common group ciphers */ - if (!((a_flags & 0xF0) & (b_flags & 0xF0))) - return FALSE; - - return TRUE; -} - NMAccessPoint * -nm_ap_match_in_hash (NMAccessPoint *find_ap, - GHashTable *hash, - gboolean strict_match) +nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash) { GHashTableIter iter; NMAccessPoint *list_ap; @@ -1243,8 +1220,7 @@ nm_ap_match_in_hash (NMAccessPoint *find_ap, continue; /* BSSID match */ - if ( (strict_match || nm_ethernet_address_is_valid (find_addr, -1)) - && nm_ethernet_address_is_valid (list_addr, -1) + if ( nm_ethernet_address_is_valid (list_addr, -1) && !nm_utils_hwaddr_matches (list_addr, -1, find_addr, -1)) continue; @@ -1260,23 +1236,11 @@ nm_ap_match_in_hash (NMAccessPoint *find_ap, if (nm_ap_get_flags (list_ap) != nm_ap_get_flags (find_ap)) continue; - if (strict_match) { - if (nm_ap_get_wpa_flags (list_ap) != nm_ap_get_wpa_flags (find_ap)) - continue; + if (nm_ap_get_wpa_flags (list_ap) != nm_ap_get_wpa_flags (find_ap)) + continue; - if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap)) - continue; - } else { - NM80211ApSecurityFlags list_wpa_flags = nm_ap_get_wpa_flags (list_ap); - NM80211ApSecurityFlags find_wpa_flags = nm_ap_get_wpa_flags (find_ap); - NM80211ApSecurityFlags list_rsn_flags = nm_ap_get_rsn_flags (list_ap); - NM80211ApSecurityFlags find_rsn_flags = nm_ap_get_rsn_flags (find_ap); - - /* Just ensure that there is overlap in the capabilities */ - if ( !capabilities_compatible (list_wpa_flags, find_wpa_flags) - && !capabilities_compatible (list_rsn_flags, find_rsn_flags)) - continue; - } + if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap)) + continue; return list_ap; } diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 01a104d669..84e5fa34e3 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -118,9 +118,7 @@ gboolean nm_ap_complete_connection (NMAccessPoint *self, gboolean lock_bssid, GError **error); -NMAccessPoint * nm_ap_match_in_hash (NMAccessPoint *find_ap, - GHashTable *hash, - gboolean strict_match); +NMAccessPoint * nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash); void nm_ap_dump (NMAccessPoint *ap, const char *prefix); From 227de48a910f1708ba6275fa5a256824b3bb07ab Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 13:04:54 -0500 Subject: [PATCH 8/9] wifi: remove unused AP 'broadcast' property Nothing ever read the value. --- src/devices/wifi/nm-device-wifi.c | 5 +---- src/devices/wifi/nm-wifi-ap.c | 25 ------------------------- src/devices/wifi/nm-wifi-ap.h | 3 --- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index ae3c91bbd7..1361bd89dd 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1506,7 +1506,6 @@ merge_scanned_ap (NMDeviceWifi *self, /* Yay, matched it, no longer treat as hidden */ _LOGD (LOGD_WIFI_SCAN, "matched hidden AP %s => '%s'", str_if_set (bssid, "(none)"), nm_utils_escape_ssid (ssid->data, ssid->len)); - nm_ap_set_broadcast (merge_ap, FALSE); } else { /* Didn't have an entry for this AP in the database */ _LOGD (LOGD_WIFI_SCAN, "failed to match hidden AP %s", @@ -2481,9 +2480,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) ap = nm_ap_new_fake_from_connection (connection); g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE); - if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA) - nm_ap_set_broadcast (ap, FALSE); - else if (nm_ap_is_hotspot (ap)) + if (nm_ap_is_hotspot (ap)) nm_ap_set_address (ap, nm_device_get_hw_address (device)); nm_ap_export_to_dbus (ap); diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 107cac77ed..91b3bcb355 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -62,7 +62,6 @@ typedef struct /* Non-scanned attributes */ gboolean fake; /* Whether or not the AP is from a scan */ gboolean hotspot; /* Whether the AP is a local device's hotspot network */ - gboolean broadcast; /* Whether or not the AP is broadcasting (hidden) */ gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ } NMAccessPointPrivate; @@ -94,7 +93,6 @@ nm_ap_init (NMAccessPoint *ap) 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->broadcast = TRUE; } static void @@ -420,9 +418,6 @@ nm_ap_update_from_properties (NMAccessPoint *ap, g_variant_unref (v); } - if (!nm_ap_get_ssid (ap)) - nm_ap_set_broadcast (ap, FALSE); - v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); if (v) { bytes = g_variant_get_fixed_array (v, &len, 1); @@ -1051,26 +1046,6 @@ void nm_ap_set_fake (NMAccessPoint *ap, gboolean fake) NM_AP_GET_PRIVATE (ap)->fake = fake; } - -/* - * Get/Set functions to indicate whether an AP broadcasts its SSID. - */ -gboolean nm_ap_get_broadcast (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), TRUE); - - return NM_AP_GET_PRIVATE (ap)->broadcast; -} - - -void nm_ap_set_broadcast (NMAccessPoint *ap, gboolean broadcast) -{ - g_return_if_fail (NM_IS_AP (ap)); - - NM_AP_GET_PRIVATE (ap)->broadcast = broadcast; -} - - /* * Get/Set functions for how long ago the AP was last seen in a scan. * APs older than a certain date are dropped from the list. diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 84e5fa34e3..bcbf7eea0e 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -104,9 +104,6 @@ void nm_ap_set_max_bitrate (NMAccessPoint *ap, guint32 bitrate); gboolean nm_ap_get_fake (const NMAccessPoint *ap); void nm_ap_set_fake (NMAccessPoint *ap, gboolean fake); -gboolean nm_ap_get_broadcast (NMAccessPoint *ap); -void nm_ap_set_broadcast (NMAccessPoint *ap, gboolean broadcast); - gint32 nm_ap_get_last_seen (const NMAccessPoint *ap); void nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen); From fbf60536f925b22719499e7cd9b057812bf63f36 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Apr 2015 13:37:22 -0500 Subject: [PATCH 9/9] wifi: fall back to band matching when frequency matching fails Some dual-band access points use the same BSSID in both the 5GHz and 2.4GHz bands, so obviously frequency must be taken into account when matching. But no AP should ever use the same SSID/BSSID pair concurrently in the same band on different frequencies. Some APs also dynamically channel hop when they detect interference, or when they restart, they do so on a different channel after finding the channel with the lowest interference. To assure that we don't end up with stale scan list entries when the AP has switched to another channel in the same band, fall back to band matching when merging new scan results. --- src/devices/wifi/nm-wifi-ap.c | 40 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 91b3bcb355..0519784c12 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -1067,6 +1067,16 @@ nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen) NM_AP_GET_PRIVATE (ap)->last_seen = last_seen; } +static guint +freq_to_band (guint32 freq) +{ + if (freq >= 4915 && freq <= 5825) + return 5; + else if (freq >= 2412 && freq <= 2484) + return 2; + return 0; +} + gboolean nm_ap_check_compatible (NMAccessPoint *self, NMConnection *connection) @@ -1117,13 +1127,12 @@ nm_ap_check_compatible (NMAccessPoint *self, band = nm_setting_wireless_get_band (s_wireless); if (band) { - if (!strcmp (band, "a")) { - if (priv->freq < 4915 || priv->freq > 5825) - return FALSE; - } else if (!strcmp (band, "bg")) { - if (priv->freq < 2412 || priv->freq > 2484) - return FALSE; - } + guint ap_band = freq_to_band (priv->freq); + + if (!strcmp (band, "a") && ap_band != 5) + return FALSE; + else if (!strcmp (band, "bg") && ap_band != 2) + return FALSE; } channel = nm_setting_wireless_get_channel (s_wireless); @@ -1169,7 +1178,7 @@ NMAccessPoint * nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash) { GHashTableIter iter; - NMAccessPoint *list_ap; + NMAccessPoint *list_ap, *band_match = NULL; g_return_val_if_fail (find_ap != NULL, NULL); @@ -1177,9 +1186,11 @@ nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash) while (g_hash_table_iter_next (&iter, NULL, (gpointer) &list_ap)) { const GByteArray * list_ssid = nm_ap_get_ssid (list_ap); const char * list_addr = nm_ap_get_address (list_ap); + const guint32 list_freq = nm_ap_get_freq (list_ap); const GByteArray * find_ssid = nm_ap_get_ssid (find_ap); const char * find_addr = nm_ap_get_address (find_ap); + const guint32 find_freq = nm_ap_get_freq (find_ap); /* SSID match; if both APs are hiding their SSIDs, * let matching continue on BSSID and other properties @@ -1203,10 +1214,6 @@ nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash) if (nm_ap_get_mode (list_ap) != nm_ap_get_mode (find_ap)) continue; - /* Frequency match */ - if (nm_ap_get_freq (list_ap) != nm_ap_get_freq (find_ap)) - continue; - /* AP flags */ if (nm_ap_get_flags (list_ap) != nm_ap_get_flags (find_ap)) continue; @@ -1217,9 +1224,16 @@ nm_ap_match_in_hash (NMAccessPoint *find_ap, GHashTable *hash) if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap)) continue; + if (list_freq != find_freq) { + /* Must be last check to ensure all other properties match */ + if (freq_to_band (list_freq) == freq_to_band (find_freq)) + band_match = list_ap; + continue; + } + return list_ap; } - return NULL; + return band_match; }