WNM: Optimize BSS transition management scans
authorJouni Malinen <j@w1.fi>
Sat, 22 Nov 2014 17:50:16 +0000 (19:50 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 22 Nov 2014 18:17:47 +0000 (20:17 +0200)
When the list of preferred transition candidates is received, use the
identified channels to optimize the following scan so that no time is
wasted on other channels.

Signed-off-by: Jouni Malinen <j@w1.fi>
wpa_supplicant/wnm_sta.c
wpa_supplicant/wnm_sta.h
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index b64a411..7aa2f7f 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
@@ -406,6 +407,12 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep,
 }
 
 
+static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
+{
+       return ieee80211_chan_to_freq(NULL, op_class, chan);
+}
+
+
 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
                                      const u8 *pos, u8 len,
                                      struct neighbor_report *rep)
@@ -442,6 +449,9 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
                left -= elen;
                pos += elen;
        }
+
+       rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
+                                    rep->channel_number);
 }
 
 
@@ -673,12 +683,82 @@ static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
 
                nei = &wpa_s->wnm_neighbor_report_elements[i];
                wpa_printf(MSG_DEBUG, "%u: " MACSTR
-                          " info=0x%x op_class=%u chan=%u phy=%u pref=%d",
+                          " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
                           i, MAC2STR(nei->bssid), nei->bssid_info,
                           nei->regulatory_class,
                           nei->channel_number, nei->phy_type,
-                          nei->preference_present ? nei->preference : -1);
+                          nei->preference_present ? nei->preference : -1,
+                          nei->freq);
+       }
+}
+
+
+static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
+{
+       unsigned int i;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+               int j;
+
+               for (j = 0; j < mode->num_channels; j++) {
+                       struct hostapd_channel_data *chan;
+
+                       chan = &mode->channels[j];
+                       if (chan->freq == freq &&
+                           !(chan->flag & HOSTAPD_CHAN_DISABLED))
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+
+static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
+{
+       int *freqs;
+       int num_freqs = 0;
+       unsigned int i;
+
+       if (!wpa_s->wnm_neighbor_report_elements)
+               return;
+
+       if (wpa_s->hw.modes == NULL)
+               return;
+
+       os_free(wpa_s->next_scan_freqs);
+       wpa_s->next_scan_freqs = NULL;
+
+       freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
+       if (freqs == NULL)
+               return;
+
+       for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+               struct neighbor_report *nei;
+
+               nei = &wpa_s->wnm_neighbor_report_elements[i];
+               if (nei->freq <= 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "WNM: Unknown neighbor operating frequency for "
+                                  MACSTR " - scan all channels",
+                                  MAC2STR(nei->bssid));
+                       os_free(freqs);
+                       return;
+               }
+               if (chan_supported(wpa_s, nei->freq))
+                       add_freq(freqs, &num_freqs, nei->freq);
        }
+
+       if (num_freqs == 0) {
+               os_free(freqs);
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "WNM: Scan %d frequencies based on transition candidate list",
+                  num_freqs);
+       wpa_s->next_scan_freqs = freqs;
 }
 
 
@@ -794,6 +874,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
                wpa_s->wnm_cand_valid_until.usec %= 1000000;
                os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
 
+               wnm_set_scan_freqs(wpa_s);
                wpa_supplicant_req_scan(wpa_s, 0, 0);
        } else if (reply) {
                enum bss_trans_mgmt_status_code status;
index a45a695..fd3a5dd 100644 (file)
@@ -45,6 +45,7 @@ struct neighbor_report {
        unsigned int bss_term_present:1;
        struct measurement_pilot *meas_pilot;
        struct multiple_bssid *mul_bssid;
+       int freq;
 };
 
 
index 8261c66..aeed3a8 100644 (file)
@@ -4402,7 +4402,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 }
 
 
-static void add_freq(int *freqs, int *num_freqs, int freq)
+void add_freq(int *freqs, int *num_freqs, int freq)
 {
        int i;
 
index a9f5d17..e52dfd9 100644 (file)
@@ -992,6 +992,7 @@ void wpas_request_connection(struct wpa_supplicant *wpa_s);
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
 int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
+void add_freq(int *freqs, int *num_freqs, int freq);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response