[RFC v2 3/3] wpa_supplicant: Report 40MHz Intolerance to associated AP.
Rajkumar Manoharan
rmanohar
Mon Jul 18 00:15:01 PDT 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 | 42 +++++++++++++++++++++++++
wpa_supplicant/sme.h | 6 ++++
wpa_supplicant/wpa_supplicant.c | 61 +++++++++++++++++++++++++++++++++++++
wpa_supplicant/wpa_supplicant_i.h | 1 +
5 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index b398792..159bd8e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -958,6 +958,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
+
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 325ffc5..5aede12 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -590,7 +590,49 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
}
+void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+ 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;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "MLME: Send 20/40 BSS Coexistence");
+
+ 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->reg_class, NULL);
+
+ if (n_channels) {
+ pos = wpabuf_put(buf, n_channels);
+ os_memcpy(pos, 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..60ccf56 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -41,6 +41,8 @@ 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,
+ u8 *chan_list, u8 n_channels);
#else /* CONFIG_SME */
static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
@@ -101,6 +103,10 @@ static inline void sme_deinit(struct wpa_supplicant *wpa_s)
{
}
+static inline void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+ 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 f303b40..3de7ea4 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -2824,3 +2824,64 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
}
+
+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;
+ Boolean found_intolerant = FALSE;
+ const u8 *ie;
+ u16 ht_cap;
+ u16 num_modes, flags;
+ u8 intol_channels[28], tmp_channel;
+ u8 n_channels = 0;
+
+ 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 || !(modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
+
+ /* Check whether AP is supporting HT40 */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+ if (!ie || !(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) {
+ /* To avoid channel duplication */
+ if (!n_channels ||
+ intol_channels[n_channels - 1] != tmp_channel)
+ intol_channels[n_channels++] = tmp_channel;
+ found_intolerant = TRUE;
+ } 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 = TRUE;
+ }
+ }
+ }
+
+ if (found_intolerant)
+ sme_send_2040_bss_coex(wpa_s, intol_channels, n_channels);
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index c1a8808..dd598ae 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -633,6 +633,7 @@ 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);
+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.6
More information about the Hostap
mailing list