diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 743abacb74..9fe51a3a0c 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -837,20 +837,35 @@ get_active_ap (NMDeviceWifi *self, static void set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMDeviceWifiPrivate *priv; char *old_path = NULL; + NMAccessPoint *old_ap; g_return_if_fail (NM_IS_DEVICE_WIFI (self)); - if (priv->current_ap) { - old_path = g_strdup (nm_ap_get_dbus_path (priv->current_ap)); - g_object_unref (priv->current_ap); + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + old_ap = priv->current_ap; + + if (old_ap) { + old_path = g_strdup (nm_ap_get_dbus_path (old_ap)); priv->current_ap = NULL; } - if (new_ap) + 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); + } + + /* Unref old AP here to ensure object lives if new_ap == old_ap */ + if (old_ap) + g_object_unref (old_ap); + /* Only notify if it's really changed */ if ( (!old_path && new_ap) || (old_path && !new_ap) @@ -867,6 +882,24 @@ periodic_update (NMDeviceWifi *self) NMAccessPoint *new_ap; guint32 new_rate; + /* 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 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)) { + struct ether_addr bssid = { {0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; + + nm_device_wifi_get_bssid (self, &bssid); + /* 0x02 is the first byte of IBSS BSSIDs */ + if ( (bssid.ether_addr_octet[0] == 0x02) + && nm_ethernet_address_is_valid (&bssid)) + nm_ap_set_address (priv->current_ap, &bssid); + } + new_ap = get_active_ap (self, NULL, FALSE); if (new_ap) nm_device_wifi_update_signal_strength (self, new_ap); @@ -1009,11 +1042,25 @@ real_take_down (NMDevice *dev) static void real_deactivate_quickly (NMDevice *dev) { - NMDeviceWifi * self = NM_DEVICE_WIFI (dev); + NMDeviceWifi *self = NM_DEVICE_WIFI (dev); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMAccessPoint *orig_ap; cleanup_association_attempt (self, TRUE); + /* If the AP is 'fake', i.e. it wasn't actually found from + * a scan but the user tried to connect to it manually (maybe it + * was non-broadcasting or something) clear the 'fake' flag here, + * becuase 'fake' APs should only live for as long as we're + * connected to them. Fixes a bug where user-created Ad-Hoc APs + * are never removed from the scan list, because scanning is + * disabled while in Ad-Hoc mode (for stability), and thus the + * AP culling never happens. (bgo #569241) + */ + orig_ap = nm_device_wifi_get_activation_ap (self); + if (orig_ap && nm_ap_get_fake (orig_ap)) + nm_ap_set_fake (orig_ap, FALSE); + set_current_ap (self, NULL); priv->rate = 0; @@ -1958,7 +2005,7 @@ merge_scanned_ap (NMDeviceWifi *self, /* New entry in the list */ // FIXME: figure out if reference counts are correct here for AP objects g_object_ref (merge_ap); - priv->ap_list = g_slist_append (priv->ap_list, merge_ap); + priv->ap_list = g_slist_prepend (priv->ap_list, merge_ap); nm_ap_export_to_dbus (merge_ap); g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, merge_ap); } @@ -2842,7 +2889,7 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) break; } - priv->ap_list = g_slist_append (priv->ap_list, ap); + priv->ap_list = g_slist_prepend (priv->ap_list, ap); nm_ap_export_to_dbus (ap); g_signal_emit (self, signals[ACCESS_POINT_ADDED], 0, ap); } @@ -3113,13 +3160,16 @@ activation_success_handler (NMDevice *dev) ap = nm_device_wifi_get_activation_ap (self); - /* 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. + /* If the AP isn't fake, it was found in the scan list and all its + * details are known. */ if (!nm_ap_get_fake (ap)) goto done; + /* 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_device_wifi_get_bssid (self, &bssid); if (!nm_ethernet_address_is_valid (nm_ap_get_address (ap))) nm_ap_set_address (ap, &bssid);