[network-manager-netbook: 1/4] Fix a bug where wrong AP would be used for connected wifi items.



commit 6b0f6413767138634906ea3f922554b1bca3d3d7
Author: Tambet Ingo <tambet gmail com>
Date:   Wed Oct 7 15:34:00 2009 +0300

    Fix a bug where wrong AP would be used for connected wifi items.

 src/nmn-wifi-handler.c |  159 +++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 123 insertions(+), 36 deletions(-)
---
diff --git a/src/nmn-wifi-handler.c b/src/nmn-wifi-handler.c
index 5f49b92..27c8bfc 100644
--- a/src/nmn-wifi-handler.c
+++ b/src/nmn-wifi-handler.c
@@ -51,6 +51,47 @@ nmn_wifi_handler_new (NmnNMData *nm_data,
                                              NULL));
 }
 
+static gboolean
+aps_are_compatible (NMAccessPoint *ap1, NMAccessPoint *ap2)
+{
+    const GByteArray *ssid1;
+    const GByteArray *ssid2;
+
+    ssid1 = nm_access_point_get_ssid (ap1);
+    ssid2 = nm_access_point_get_ssid (ap2);
+
+    /* SSIDs do not match */
+    if (!ssid1 || !ssid2 || ssid1->len != ssid2->len || memcmp (ssid1->data, ssid2->data, ssid1->len))
+        return FALSE;
+
+    if (nm_access_point_get_mode (ap1) == nm_access_point_get_mode (ap2) &&
+        nm_access_point_get_flags (ap1) == nm_access_point_get_flags (ap2) &&
+        nm_access_point_get_wpa_flags (ap1) == nm_access_point_get_wpa_flags (ap2) &&
+        nm_access_point_get_rsn_flags (ap1) == nm_access_point_get_rsn_flags (ap2))
+        return TRUE;
+
+    return FALSE;
+}
+
+static NMAccessPoint *
+find_best_compatible_ap (const GPtrArray *aps, NMAccessPoint *current_ap)
+{
+    NMAccessPoint *best_ap = NULL;
+    int i;
+
+    for (i = 0; aps && i < aps->len; i++) {
+        NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i));
+
+        if (ap == current_ap || !aps_are_compatible (current_ap, ap))
+            continue;
+
+        if (!best_ap || nm_access_point_get_strength (best_ap) < nm_access_point_get_strength (ap))
+            best_ap = ap;
+    }
+
+    return best_ap;
+}
+
 static NMAccessPoint *
 find_best_ap_for_connection (NMDeviceWifi *device,
                              NMExportedConnection *connection)
@@ -77,50 +118,64 @@ find_best_ap_for_connection (NMDeviceWifi *device,
 }
 
 static void
-update_items (NmnWifiHandler *self)
+ap_updated (NMAccessPoint *ap,
+            GParamSpec *pspec,
+            gpointer user_data)
 {
-    GSList *list;
+    NmnDeviceHandler *handler = NMN_DEVICE_HANDLER (user_data);
+    GSList *items;
     GSList *iter;
-    NMDeviceWifi *device;
-
-    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (NMN_DEVICE_HANDLER (self)));
-    list = nmn_device_handler_get_items (NMN_DEVICE_HANDLER (self));
 
-    for (iter = list; iter; iter = iter->next) {
+    items = nmn_device_handler_get_items (handler);
+    for (iter = items; iter; iter = iter->next) {
         NmnWifiItem *item = NMN_WIFI_ITEM (iter->data);
-        NMAccessPoint *current_ap = nmn_wifi_item_get_ap (item);
-        NMAccessPoint *best_ap;
-
-        best_ap = nm_device_wifi_get_active_access_point (device);
-        if (!best_ap) {
-            NMExportedConnection *exported;
-
-            exported = nmn_network_item_get_connection (NMN_NETWORK_ITEM (item));
-            best_ap = find_best_ap_for_connection (device, exported);
-        }
-
-        if (!best_ap)
-            nmn_item_remove_requested (NMN_ITEM (item));
-        else if (best_ap != current_ap)
-            nmn_wifi_item_set_ap (item, best_ap);
+        NMAccessPoint *item_ap = nmn_wifi_item_get_ap (item);
+        NMDeviceWifi *device;
+        NMAccessPoint *new_ap;
+
+        /* Don't touch activated items, these are handled by active_ap_changed */
+        if (nmn_network_item_get_status (NMN_NETWORK_ITEM (item)) != NMN_NETWORK_ITEM_STATUS_DISCONNECTED)
+            continue;
+
+        /* not us */
+        if (item_ap != ap && !aps_are_compatible (ap, item_ap))
+            continue;
+
+        /* Do we have a better compatible AP for this item? */
+        device = NM_DEVICE_WIFI (nmn_device_handler_get_device (handler));
+        new_ap = find_best_compatible_ap (nm_device_wifi_get_access_points (device), item_ap);
+        if (new_ap)
+            nmn_wifi_item_set_ap (item, new_ap);
     }
 }
 
 static void
-ap_updated (NMAccessPoint *ap,
-            GParamSpec *pspec,
-            gpointer user_data)
-{
-    update_items (NMN_WIFI_HANDLER (user_data));
-}
-
-static void
 ap_removed (NMDeviceWifi *device,
             NMAccessPoint *ap,
             gpointer user_data)
 {
+    GSList *items;
+    GSList *iter;
+
     g_signal_handlers_disconnect_by_func (ap, "notify", ap_updated);
-    update_items (NMN_WIFI_HANDLER (user_data));
+
+    items = nmn_device_handler_get_items (NMN_DEVICE_HANDLER (user_data));
+    for (iter = items; iter; iter = iter->next) {
+        NmnWifiItem *item = NMN_WIFI_ITEM (iter->data);
+        NMAccessPoint *new_ap;
+
+        /* not us */
+        if (nmn_wifi_item_get_ap (item) != ap)
+            continue;
+
+        /* Do we have another compatible AP for this item? */
+        new_ap = find_best_compatible_ap (nm_device_wifi_get_access_points (device), ap);
+        if (new_ap)
+            nmn_wifi_item_set_ap (item, new_ap);
+        else
+            /* Nope, remove the item */
+            nmn_item_remove_requested (NMN_ITEM (item));
+    }
 }
 
 static void
@@ -166,10 +221,8 @@ ap_added (NMDeviceWifi *device,
     GSList *iter;
 
     /* Catch the signals of the new AP */
-    g_signal_connect (ap, "notify", G_CALLBACK (ap_updated), handler);
-
-    /* */
-    update_items (NMN_WIFI_HANDLER (handler));
+    g_signal_connect (ap, "notify", G_CALLBACK (ap_updated), user_data);
+    ap_updated (ap, NULL, user_data);
 
     /* Maybe there's an existing connection for it which hasn't been added yet? */
     list = nmn_device_handler_get_connections (handler);
@@ -179,12 +232,46 @@ ap_added (NMDeviceWifi *device,
     g_slist_free (list);
 }
 
+static gboolean
+active_ap_changed_cb (gpointer user_data)
+{
+    NmnDeviceHandler *handler = NMN_DEVICE_HANDLER (user_data);
+    NMDeviceWifi *device;
+    GSList *items;
+    GSList *iter;
+    NMAccessPoint *active_ap;
+
+    device = NM_DEVICE_WIFI (nmn_device_handler_get_device (handler));
+    active_ap = nm_device_wifi_get_active_access_point (device);
+    items = nmn_device_handler_get_items (NMN_DEVICE_HANDLER (user_data));
+
+    for (iter = items; iter; iter = iter->next) {
+        NmnWifiItem *item = NMN_WIFI_ITEM (iter->data);
+
+        /* Don't touch inactive items */
+        if (nmn_network_item_get_status (NMN_NETWORK_ITEM (item)) == NMN_NETWORK_ITEM_STATUS_DISCONNECTED)
+            continue;
+
+        /* If an item gets deactivated, find a new best AP for it */
+        if (!active_ap)
+            active_ap = find_best_compatible_ap (nm_device_wifi_get_access_points (device),
+                                                 nmn_wifi_item_get_ap (item));
+
+        if (active_ap && nmn_wifi_item_get_ap (item) != active_ap)
+            nmn_wifi_item_set_ap (item, active_ap);
+    }
+
+    return FALSE;
+}
+
 static void
 active_ap_changed (NMDeviceWifi *device,
                    GParamSpec *pspec,
                    gpointer user_data)
 {
-    update_items (NMN_WIFI_HANDLER (user_data));
+    /* We need to delay this a bit, otherwise we haven't received all the other state
+       change notification yet and we don't know the correct state */
+    g_timeout_add_seconds (2, active_ap_changed_cb, user_data);
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]