[PATCH 3/4] wpa_supplicant: Report 40MHz Intolerance to associated AP

Rajkumar Manoharan rmanohar at qca.qualcomm.com
Wed Oct 5 15:12:00 EDT 2011


This patch adds support for 40MHz intolerance handling in STA
mode. STA should report of any 40MHz intolerance in case if it
finds a non-HT AP or a HT AP which prohibits 40MHz transmission
(i.e 40MHz intolerant bit is set in HT capabilities IE).

STA shall report this condition using 20/40 BSS coexistence
action frame.

Signed-off-by: Rajkumar Manoharan <rmanohar at qca.qualcomm.com>
---
 wpa_supplicant/events.c           |    4 ++
 wpa_supplicant/sme.c              |   44 +++++++++++++++++++++++
 wpa_supplicant/sme.h              |    8 ++++
 wpa_supplicant/wpa_supplicant.c   |   70 +++++++++++++++++++++++++++++++++++++
 wpa_supplicant/wpa_supplicant_i.h |    1 +
 5 files changed, 127 insertions(+), 0 deletions(-)

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7d886e7..54ef8ae 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -968,6 +968,10 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
 
 	selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
 
+#ifdef CONFIG_SME
+	wpa_supplicant_proc_40mhz_intolerant(wpa_s);
+#endif /* CONFIG_SME */
+
 	if (selected) {
 		int skip;
 		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index dbf385e..3b7f27e 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -592,6 +592,50 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
 }
 
 
+void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+			    const u8 *chan_list, u8 n_channels)
+{
+	struct ieee80211_2040_bss_coex_ie *bc_ie;
+	struct ieee80211_2040_intol_chan_report *ic_report;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "SME: Send 20/40 BSS Coexistence to " MACSTR,
+		   MAC2STR(wpa_s->bssid));
+
+	buf = wpabuf_alloc(2 + /* action.category + action_code */
+			   sizeof(struct ieee80211_2040_bss_coex_ie) +
+			   sizeof(struct ieee80211_2040_intol_chan_report) +
+			   n_channels);
+	if (buf == NULL)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, WLAN_PA_20_40_BSS_COEX);
+
+	bc_ie = wpabuf_put(buf, sizeof(*bc_ie));
+	bc_ie->element_id = WLAN_EID_20_40_BSS_COEXISTENCE;
+	bc_ie->length = 1;
+	bc_ie->coex_param = WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ;
+
+	ic_report = wpabuf_put(buf, sizeof(*ic_report));
+	ic_report->element_id = WLAN_EID_20_40_BSS_INTOLERANT;
+	ic_report->length = n_channels + 1;
+	freq_to_channel(wpa_s->current_bss->freq, &ic_report->op_class, NULL);
+
+	if (n_channels)
+		os_memcpy(wpabuf_put(buf, n_channels), chan_list, n_channels);
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf)) < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send 20/40 BSS "
+			"Coexistence frame");
+	}
+
+	wpabuf_free(buf);
+}
+
+
 #ifdef CONFIG_IEEE80211W
 
 static const unsigned int sa_query_max_timeout = 1000;
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index a59b38d..bb5887b 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -41,6 +41,9 @@ void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
 				       const u8 *prev_pending_bssid);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
+void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+			    const u8 *chan_list, u8 n_channels);
+
 #else /* CONFIG_SME */
 
 static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -101,6 +104,11 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 }
 
+static inline void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+					  const u8 *chan_list, u8 n_channels)
+{
+}
+
 #endif /* CONFIG_SME */
 
 #endif /* SME_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 3cf62e8..b4b8034 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2877,3 +2877,73 @@ int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
 	return wpa_s->conf->ap_scan == 2 ||
 		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
 }
+
+
+#ifdef CONFIG_SME
+void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	struct hostapd_hw_modes *modes;
+	enum wpas_band assoc_band;
+	int found_intolerant = 0;
+	const u8 *ie;
+	u16 ht_cap;
+	u16 num_modes, flags;
+	u8 intol_channels[28], tmp_channel;
+	u8 n_channels = 0;
+	u16 ht_capab;
+
+	if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+		return;
+
+	/* Check whether local driver supports HT40 */
+	modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
+	if (!modes)
+		return;
+	ht_capab = modes->ht_capab;
+	ieee80211_sta_free_hw_features(modes, num_modes);
+	if (!(ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+		return;
+
+	/* Check whether AP supports HT40 */
+	ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+	if (!ie || ie[1] < 2 ||
+	    !(ie[3] & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH))
+		return;
+
+	os_memset(intol_channels, 0, sizeof(intol_channels));
+
+	assoc_band = freq_to_channel(wpa_s->current_bss->freq, NULL, NULL);
+	if (assoc_band == WPAS_BAND_INVALID)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		/* Skip other band bss */
+		if (freq_to_channel(bss->freq, NULL, &tmp_channel) !=
+		    assoc_band)
+			continue;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+		if (!ie || ie[1] < 2) {
+			/* To avoid channel duplication */
+			if (!n_channels ||
+			    intol_channels[n_channels - 1] != tmp_channel)
+				intol_channels[n_channels++] = tmp_channel;
+			found_intolerant++;
+		} else {
+			ht_cap = WPA_GET_LE16(ie + 2);
+			if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT) {
+				/* To avoid channel duplication */
+				if (!n_channels ||
+				    intol_channels[n_channels - 1]
+					!= tmp_channel)
+					intol_channels[n_channels++] =
+						tmp_channel;
+				found_intolerant++;
+			}
+		}
+	}
+
+	if (found_intolerant)
+		sme_send_2040_bss_coex(wpa_s, intol_channels, n_channels);
+}
+#endif /* CONFIG_SME */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 866649b..353c557 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -652,6 +652,7 @@ 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);
 int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
 
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
-- 
1.7.4.1




More information about the HostAP mailing list