]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Extend load balancing optimization in BSS blacklisting
authorJouni Malinen <jouni.malinen@atheros.com>
Fri, 26 Nov 2010 09:36:03 +0000 (11:36 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 26 Nov 2010 09:36:03 +0000 (11:36 +0200)
Move the previously SME specific optimization code into generic
function that can be used from non-SME code, too, and use it to
handle disconnection events. In other words, allow disconnection
event to trigger similar optimized scanning case to handle a
common load balancing mechanism. If there is another BSS in the
same ESS when we receive a disconnection event, scan only the
known frequencies of such other BSSes on the next attempt to
speed up recovery.

wpa_supplicant/events.c
wpa_supplicant/sme.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 8b2979c6db16cfe365b4d54a7b6b33edbdfc5f3d..fe41c3bf53fa09a0eab37221b8f1440c66c0160d 100644 (file)
@@ -1310,7 +1310,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
        bssid = wpa_s->bssid;
        if (is_zero_ether_addr(bssid))
                bssid = wpa_s->pending_bssid;
-       wpa_blacklist_add(wpa_s, bssid);
+       wpas_connection_failed(wpa_s, bssid);
        wpa_sm_notify_disassoc(wpa_s->wpa);
        wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
                " reason=%d",
index 604b0a5a747189c233e892e8e5e3caa3f70bf16b..02b76395bc49eae0c757f20de8f0b9896dd57d1f 100644 (file)
 #include "scan.h"
 #include "sme.h"
 
-static void add_freq(int *freqs, int *num_freqs, int freq)
-{
-       int i;
-
-       for (i = 0; i < *num_freqs; i++) {
-               if (freqs[i] == freq)
-                       return;
-       }
-
-       freqs[*num_freqs] = freq;
-       (*num_freqs)++;
-}
-
-
-static int * sme_another_bss_in_ess(struct wpa_supplicant *wpa_s)
-{
-       struct wpa_bss *bss, *cbss;
-       const int max_freqs = 10;
-       int *freqs;
-       int num_freqs = 0;
-
-       freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
-       if (freqs == NULL)
-               return NULL;
-
-       cbss = wpa_s->current_bss;
-
-       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-               if (bss == cbss)
-                       continue;
-               if (bss->ssid_len == cbss->ssid_len &&
-                   os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
-                   wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
-                       add_freq(freqs, &num_freqs, bss->freq);
-                       if (num_freqs == max_freqs)
-                               break;
-               }
-       }
-
-       if (num_freqs == 0) {
-               os_free(freqs);
-               freqs = NULL;
-       }
-
-       return freqs;
-}
-
-
-static void sme_connection_failed(struct wpa_supplicant *wpa_s,
-                                 const u8 *bssid)
-{
-       int timeout;
-       int count;
-       int *freqs = NULL;
-
-       /*
-        * Add the failed BSSID into the blacklist and speed up next scan
-        * attempt if there could be other APs that could accept association.
-        * The current blacklist count indicates how many times we have tried
-        * connecting to this AP and multiple attempts mean that other APs are
-        * either not available or has already been tried, so that we can start
-        * increasing the delay here to avoid constant scanning.
-        */
-       count = wpa_blacklist_add(wpa_s, bssid);
-       if (count == 1 && wpa_s->current_bss) {
-               /*
-                * This BSS was not in the blacklist before. If there is
-                * another BSS available for the same ESS, we should try that
-                * next. Otherwise, we may as well try this one once more
-                * before allowing other, likely worse, ESSes to be considered.
-                */
-               freqs = sme_another_bss_in_ess(wpa_s);
-               if (freqs) {
-                       wpa_printf(MSG_DEBUG, "SME: Another BSS in this ESS "
-                                  "has been seen; try it next");
-                       wpa_blacklist_add(wpa_s, bssid);
-                       /*
-                        * On the next scan, go through only the known channels
-                        * used in this ESS based on previous scans to speed up
-                        * common load balancing use case.
-                        */
-                       os_free(wpa_s->next_scan_freqs);
-                       wpa_s->next_scan_freqs = freqs;
-               }
-       }
-
-       switch (count) {
-       case 1:
-               timeout = 100;
-               break;
-       case 2:
-               timeout = 500;
-               break;
-       case 3:
-               timeout = 1000;
-               break;
-       default:
-               timeout = 5000;
-       }
-
-       /*
-        * TODO: if more than one possible AP is available in scan results,
-        * could try the other ones before requesting a new scan.
-        */
-       wpa_supplicant_req_scan(wpa_s, timeout / 1000,
-                               1000 * (timeout % 1000));
-}
-
-
 void sme_authenticate(struct wpa_supplicant *wpa_s,
                      struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
@@ -405,7 +296,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data)
                    WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG ||
                    wpa_s->sme.auth_alg == data->auth.auth_type ||
                    wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) {
-                       sme_connection_failed(wpa_s, wpa_s->pending_bssid);
+                       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
                        return;
                }
 
@@ -562,7 +453,7 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
        }
        wpa_s->sme.prev_bssid_set = 0;
 
-       sme_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        os_memset(wpa_s->bssid, 0, ETH_ALEN);
        os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
@@ -575,7 +466,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
                              union wpa_event_data *data)
 {
        wpa_printf(MSG_DEBUG, "SME: Authentication timed out");
-       sme_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
 }
 
 
@@ -583,7 +474,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
                               union wpa_event_data *data)
 {
        wpa_printf(MSG_DEBUG, "SME: Association timed out");
-       sme_connection_failed(wpa_s, wpa_s->pending_bssid);
+       wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
        wpa_supplicant_mark_disassoc(wpa_s);
 }
 
index e9909118683d7c4d0586e911664c6602229272ef..350ad9a71bd7ced4e25894a46ac23abde9ebe9f6 100644 (file)
@@ -2543,3 +2543,111 @@ void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
 
        os_free(hw_features);
 }
+
+
+static void add_freq(int *freqs, int *num_freqs, int freq)
+{
+       int i;
+
+       for (i = 0; i < *num_freqs; i++) {
+               if (freqs[i] == freq)
+                       return;
+       }
+
+       freqs[*num_freqs] = freq;
+       (*num_freqs)++;
+}
+
+
+static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
+{
+       struct wpa_bss *bss, *cbss;
+       const int max_freqs = 10;
+       int *freqs;
+       int num_freqs = 0;
+
+       freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+       if (freqs == NULL)
+               return NULL;
+
+       cbss = wpa_s->current_bss;
+
+       dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               if (bss == cbss)
+                       continue;
+               if (bss->ssid_len == cbss->ssid_len &&
+                   os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
+                   wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+                       add_freq(freqs, &num_freqs, bss->freq);
+                       if (num_freqs == max_freqs)
+                               break;
+               }
+       }
+
+       if (num_freqs == 0) {
+               os_free(freqs);
+               freqs = NULL;
+       }
+
+       return freqs;
+}
+
+
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+       int timeout;
+       int count;
+       int *freqs = NULL;
+
+       /*
+        * Add the failed BSSID into the blacklist and speed up next scan
+        * attempt if there could be other APs that could accept association.
+        * The current blacklist count indicates how many times we have tried
+        * connecting to this AP and multiple attempts mean that other APs are
+        * either not available or has already been tried, so that we can start
+        * increasing the delay here to avoid constant scanning.
+        */
+       count = wpa_blacklist_add(wpa_s, bssid);
+       if (count == 1 && wpa_s->current_bss) {
+               /*
+                * This BSS was not in the blacklist before. If there is
+                * another BSS available for the same ESS, we should try that
+                * next. Otherwise, we may as well try this one once more
+                * before allowing other, likely worse, ESSes to be considered.
+                */
+               freqs = get_bss_freqs_in_ess(wpa_s);
+               if (freqs) {
+                       wpa_printf(MSG_DEBUG, "Another BSS in this ESS has "
+                                  "been seen; try it next");
+                       wpa_blacklist_add(wpa_s, bssid);
+                       /*
+                        * On the next scan, go through only the known channels
+                        * used in this ESS based on previous scans to speed up
+                        * common load balancing use case.
+                        */
+                       os_free(wpa_s->next_scan_freqs);
+                       wpa_s->next_scan_freqs = freqs;
+               }
+       }
+
+       switch (count) {
+       case 1:
+               timeout = 100;
+               break;
+       case 2:
+               timeout = 500;
+               break;
+       case 3:
+               timeout = 1000;
+               break;
+       default:
+               timeout = 5000;
+       }
+
+       /*
+        * TODO: if more than one possible AP is available in scan results,
+        * could try the other ones before requesting a new scan.
+        */
+       wpa_supplicant_req_scan(wpa_s, timeout / 1000,
+                               1000 * (timeout % 1000));
+}
index 4c6fa4ff371507233c048d1e67f6c8a0bf7252af..582df697e0f9f87a70ceef017944799e2f8d6a54 100644 (file)
@@ -607,6 +607,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
 void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
                                    size_t num_hw_features);
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
 
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);