SME: Optimize OBSS scanning
authorJouni Malinen <j@w1.fi>
Mon, 22 Dec 2014 20:07:03 +0000 (22:07 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 22 Dec 2014 20:07:03 +0000 (22:07 +0200)
Include only the potentially affected channel range in OBSS scans to
reduce the amount of offchannel time needed for scanning when requested
by the AP.

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

index 011b605..53caade 100644 (file)
@@ -1253,28 +1253,72 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 }
 
 
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
-                                       enum hostapd_hw_mode band,
-                                       struct wpa_driver_scan_params *params)
+static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
+                                    struct wpa_driver_scan_params *params)
 {
-       /* Include only supported channels for the specified band */
+       /* Include only affected channels */
        struct hostapd_hw_modes *mode;
        int count, i;
+       int start, end;
 
-       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+       mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+                       HOSTAPD_MODE_IEEE80211G);
        if (mode == NULL) {
                /* No channels supported in this band - use empty list */
                params->freqs = os_zalloc(sizeof(int));
                return;
        }
 
+       if (wpa_s->sme.ht_sec_chan == HT_SEC_CHAN_UNKNOWN &&
+           wpa_s->current_bss) {
+               const u8 *ie;
+
+               ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+               if (ie && ie[1] >= 2) {
+                       u8 o;
+
+                       o = ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+                       if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+                               wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+                       else if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+                               wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+               }
+       }
+
+       start = wpa_s->assoc_freq - 10;
+       end = wpa_s->assoc_freq + 10;
+       switch (wpa_s->sme.ht_sec_chan) {
+       case HT_SEC_CHAN_UNKNOWN:
+               /* HT40+ possible on channels 1..9 */
+               if (wpa_s->assoc_freq <= 2452)
+                       start -= 20;
+               /* HT40- possible on channels 5-13 */
+               if (wpa_s->assoc_freq >= 2432)
+                       end += 20;
+               break;
+       case HT_SEC_CHAN_ABOVE:
+               end += 20;
+               break;
+       case HT_SEC_CHAN_BELOW:
+               start -= 20;
+               break;
+       }
+       wpa_printf(MSG_DEBUG,
+                  "OBSS: assoc_freq %d possible affected range %d-%d",
+                  wpa_s->assoc_freq, start, end);
+
        params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
        if (params->freqs == NULL)
                return;
        for (count = 0, i = 0; i < mode->num_channels; i++) {
+               int freq;
+
                if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
                        continue;
-               params->freqs[count++] = mode->channels[i].freq;
+               freq = mode->channels[i].freq;
+               if (freq - 10 >= end || freq + 10 <= start)
+                       continue; /* not affected */
+               params->freqs[count++] = freq;
        }
 }
 
@@ -1290,7 +1334,7 @@ static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx)
        }
 
        os_memset(&params, 0, sizeof(params));
-       wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+       wpa_obss_scan_freqs_list(wpa_s, &params);
        params.low_priority = 1;
        wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
 
@@ -1315,6 +1359,7 @@ void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable)
 
        eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
        wpa_s->sme.sched_obss_scan = 0;
+       wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
        if (!enable)
                return;
 
index b0f3866..52137d4 100644 (file)
@@ -675,6 +675,9 @@ struct wpa_supplicant {
                                        * SA Query transaction identifiers */
                struct os_reltime sa_query_start;
                struct os_reltime last_unprot_disconnect;
+               enum { HT_SEC_CHAN_UNKNOWN,
+                      HT_SEC_CHAN_ABOVE,
+                      HT_SEC_CHAN_BELOW } ht_sec_chan;
                u8 sched_obss_scan;
                u16 obss_scan_int;
                u16 bss_max_idle_period;