STA OBSS: add check for overlapping BSSs
diff mbox series

Message ID 20190319123550.2102-1-sergey.matyukevich.os@quantenna.com
State New
Headers show
Series
  • STA OBSS: add check for overlapping BSSs
Related show

Commit Message

Sergey Matyukevich March 19, 2019, 12:35 p.m. UTC
In the current implementation connected STA performs OBSS scan according
to requests from its 20/40 MHz AP. However STA checks only 40MHz intolerance
bit from HT_CAP IE in scan results. Meanwhile, as per to 802.11 standard,
STA should check overlapping BSSs as well.

Note that all the required code to check overlapping BSSs is already exists
in hostapd source tree since AP does those checks properly before operating
as 20/40 MHz BSS in 2.4G band. So this commit makes use of existing code
by doing the following changes:
- extract new check_bss_coex_40mhz function from check_40mhz_2g4
- replace existing 40MHz intolerance check in sme_proc_obss_scan
  by new check_bss_coex_40mhz function

Signed-off-by: Sergey Matyukevich <sergey.matyukevich.os@quantenna.com>
---
 src/common/hw_features_common.c | 132 ++++++++++++++++++++++------------------
 src/common/hw_features_common.h |   1 +
 wpa_supplicant/events.c         |   2 +-
 wpa_supplicant/sme.c            |  52 ++++++++++------
 wpa_supplicant/sme.h            |   6 +-
 5 files changed, 113 insertions(+), 80 deletions(-)

Patch
diff mbox series

diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 49ed80657..e76edf106 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -273,6 +273,78 @@  static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
 }
 
 
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq)
+{
+	int affected_start, affected_end;
+	struct ieee802_11_elems elems;
+	int pri_chan, sec_chan;
+	int pri = bss->freq;
+	int sec = pri;
+
+	if (pri_freq == sec_freq)
+		return 0;
+
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+
+	/* Check for overlapping 20 MHz BSS */
+	if (check_20mhz_bss(bss, pri_freq, affected_start,
+			    affected_end)) {
+		wpa_printf(MSG_DEBUG,
+			   "Overlapping 20 MHz BSS is found");
+		return 0;
+	}
+
+	get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+	if (sec_chan) {
+		if (sec_chan < pri_chan)
+			sec = pri - 20;
+		else
+			sec = pri + 20;
+	}
+
+	if ((pri < affected_start || pri > affected_end) &&
+	    (sec < affected_start || sec > affected_end))
+		return 1; /* not within affected channel range */
+
+	wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+		   " freq=%d pri=%d sec=%d",
+		   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+	if (sec_chan) {
+		if (pri_freq != pri || sec_freq != sec) {
+			wpa_printf(MSG_DEBUG,
+				   "40 MHz pri/sec mismatch with BSS "
+				   MACSTR
+				   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+				   MAC2STR(bss->bssid),
+				   pri, sec, pri_chan,
+				   sec > pri ? '+' : '-',
+				   pri_freq, sec_freq);
+			return 0;
+		}
+	}
+
+	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+			       0);
+	if (elems.ht_capabilities) {
+		struct ieee80211_ht_capabilities *ht_cap =
+			(struct ieee80211_ht_capabilities *)
+			elems.ht_capabilities;
+
+		if (le_to_host16(ht_cap->ht_capabilities_info) &
+		    HT_CAP_INFO_40MHZ_INTOLERANT) {
+			wpa_printf(MSG_DEBUG,
+				   "40 MHz Intolerant is set on channel %d in BSS "
+				   MACSTR, pri, MAC2STR(bss->bssid));
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
 int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 		    struct wpa_scan_results *scan_res, int pri_chan,
 		    int sec_chan)
@@ -293,67 +365,11 @@  int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
 		   affected_start, affected_end);
 	for (i = 0; i < scan_res->num; i++) {
-		struct wpa_scan_res *bss = scan_res->res[i];
-		int pri = bss->freq;
-		int sec = pri;
-		struct ieee802_11_elems elems;
-
-		/* Check for overlapping 20 MHz BSS */
-		if (check_20mhz_bss(bss, pri_freq, affected_start,
-				    affected_end)) {
-			wpa_printf(MSG_DEBUG,
-				   "Overlapping 20 MHz BSS is found");
+		if (!check_bss_coex_40mhz(scan_res->res[i], pri_freq, sec_freq))
 			return 0;
-		}
-
-		get_pri_sec_chan(bss, &pri_chan, &sec_chan);
-
-		if (sec_chan) {
-			if (sec_chan < pri_chan)
-				sec = pri - 20;
-			else
-				sec = pri + 20;
-		}
-
-		if ((pri < affected_start || pri > affected_end) &&
-		    (sec < affected_start || sec > affected_end))
-			continue; /* not within affected channel range */
-
-		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
-			   " freq=%d pri=%d sec=%d",
-			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
-
-		if (sec_chan) {
-			if (pri_freq != pri || sec_freq != sec) {
-				wpa_printf(MSG_DEBUG,
-					   "40 MHz pri/sec mismatch with BSS "
-					   MACSTR
-					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
-					   MAC2STR(bss->bssid),
-					   pri, sec, pri_chan,
-					   sec > pri ? '+' : '-',
-					   pri_freq, sec_freq);
-				return 0;
-			}
-		}
-
-		ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
-				       0);
-		if (elems.ht_capabilities) {
-			struct ieee80211_ht_capabilities *ht_cap =
-				(struct ieee80211_ht_capabilities *)
-				elems.ht_capabilities;
-
-			if (le_to_host16(ht_cap->ht_capabilities_info) &
-			    HT_CAP_INFO_40MHZ_INTOLERANT) {
-				wpa_printf(MSG_DEBUG,
-					   "40 MHz Intolerant is set on channel %d in BSS "
-					   MACSTR, pri, MAC2STR(bss->bssid));
-				return 0;
-			}
-		}
 	}
 
+
 	return 1;
 }
 
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index eb1f1c57f..256b86cbf 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -43,5 +43,6 @@  u32 num_chan_to_bw(int num_chans);
 int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
 		    int ht40_plus, int pri);
 int chan_pri_allowed(const struct hostapd_channel_data *chan);
+int check_bss_coex_40mhz(struct wpa_scan_res *bss, int pri_freq, int sec_freq);
 
 #endif /* HW_FEATURES_COMMON_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a46ef187c..4127be231 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1901,7 +1901,7 @@  static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 	if (wnm_scan_process(wpa_s, 1) > 0)
 		goto scan_work_done;
 
-	if (sme_proc_obss_scan(wpa_s) > 0)
+	if (sme_proc_obss_scan(wpa_s, scan_res) > 0)
 		goto scan_work_done;
 
 	if (own_request && data &&
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index c435bf305..761449976 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -13,6 +13,7 @@ 
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/ocv.h"
+#include "common/hw_features_common.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "common/wpa_common.h"
 #include "common/sae.h"
@@ -2049,13 +2050,14 @@  static void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
 }
 
 
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res)
 {
-	struct wpa_bss *bss;
+	u8 chan_list[P2P_MAX_CHANNELS];
+	u8 num_channels = 0, num_intol = 0;
+	int pri_freq, sec_freq;
 	const u8 *ie;
-	u16 ht_cap;
-	u8 chan_list[P2P_MAX_CHANNELS], channel;
-	u8 num_channels = 0, num_intol = 0, i;
+	int i, c;
 
 	if (!wpa_s->sme.sched_obss_scan)
 		return 0;
@@ -2083,30 +2085,42 @@  int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
 
 	os_memset(chan_list, 0, sizeof(chan_list));
 
-	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
-		/* Skip other band bss */
+	pri_freq = wpa_s->assoc_freq;
+
+	switch (wpa_s->sme.ht_sec_chan) {
+	case HT_SEC_CHAN_ABOVE:
+		sec_freq = pri_freq + 20;
+		break;
+	case HT_SEC_CHAN_BELOW:
+		sec_freq = pri_freq - 20;
+		break;
+	case HT_SEC_CHAN_UNKNOWN:
+	default:
+		wpa_msg(wpa_s, MSG_WARNING, "Undefined secondary channel: drop OBSS results");
+		return 1;
+	}
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
 		enum hostapd_hw_mode mode;
+		u8 channel;
+
+		/* Skip other band bss */
 		mode = ieee80211_freq_to_chan(bss->freq, &channel);
 		if (mode != HOSTAPD_MODE_IEEE80211G &&
 		    mode != HOSTAPD_MODE_IEEE80211B)
 			continue;
 
-		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
-		ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
-		wpa_printf(MSG_DEBUG, "SME OBSS scan BSS " MACSTR
-			   " freq=%u chan=%u ht_cap=0x%x",
-			   MAC2STR(bss->bssid), bss->freq, channel, ht_cap);
-
-		if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
-			if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)
-				num_intol++;
+		if (!check_bss_coex_40mhz(bss, pri_freq, sec_freq)) {
+			num_intol++;
 
 			/* Check whether the channel is already considered */
-			for (i = 0; i < num_channels; i++) {
-				if (channel == chan_list[i])
+			for (c = 0; c < num_channels; c++) {
+				if (channel == chan_list[c])
 					break;
 			}
-			if (i != num_channels)
+
+			if (c != num_channels)
 				continue;
 
 			chan_list[num_channels++] = channel;
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 1a7f9e832..42d5a8317 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -37,7 +37,8 @@  void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
 void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
-int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res);
 void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
 void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
 			       union wpa_event_data *data);
@@ -112,7 +113,8 @@  static inline void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 }
 
-static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_scan_results *scan_res)
 {
 	return 0;
 }