[RFC 2/3] wpa_supplicant: Add 2040 BSS intolerance support in station mode
Rajkumar Manoharan
rmanohar
Wed Apr 18 06:44:09 PDT 2012
Add support for HT STA to report 40MHz intolerance to the associated AP.
A HT station generates a report (2040 BSS coexistence) of channel list
if it finds a non-HT capable AP or a HT AP which prohibits 40MHz
transmission (i.e 40MHz intolerant bit is set in HT capabilities IE)
from the scan results.
Signed-off-by: Rajkumar Manoharan <rmanohar at qca.qualcomm.com>
---
wpa_supplicant/events.c | 4 ++
wpa_supplicant/sme.c | 42 +++++++++++++++++
wpa_supplicant/sme.h | 8 ++++
wpa_supplicant/wpa_supplicant.c | 92 +++++++++++++++++++++++++++++++++++++
wpa_supplicant/wpa_supplicant_i.h | 1 +
wpa_supplicant/wps_supplicant.h | 11 +++++
6 files changed, 158 insertions(+)
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 8fdc544..8018a69 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1096,6 +1096,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 b366847..8f5f628 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -609,6 +609,48 @@ void sme_deinit(struct wpa_supplicant *wpa_s)
}
+void sme_send_2040_bss_coex(struct wpa_supplicant *wpa_s,
+ const u8 *chan_list, u8 num_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) +
+ num_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 = num_channels + 1;
+
+ os_memcpy(wpabuf_put(buf, num_channels), chan_list, num_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) < 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 33530bb..8bdb638 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -35,6 +35,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,
@@ -95,6 +98,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 c5a7115..5d4de3c 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3216,3 +3216,95 @@ 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
+/**
+ * freq_to_channel - Convert frequency into channel info
+ * @channel: Buffer for returning channel number
+ * Returns: Band (2 or 5 GHz)
+ */
+static enum wpas_band freq_to_channel(int freq, u8 *channel)
+{
+ enum wpas_band band = (freq <= 2484) ? WPAS_BAND_2GHZ : WPAS_BAND_5GHZ;
+ u8 chan = 0;
+
+ if (freq >= 2412 && freq <= 2472)
+ chan = (freq - 2407) / 5;
+ else if (freq == 2484)
+ chan = 14;
+ else if (freq >= 5180 && freq <= 5805)
+ chan = (freq - 5000) / 5;
+
+ *channel = chan;
+ return band;
+}
+
+void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss;
+ enum wpas_band assoc_band;
+ const u8 *ie;
+ u16 ht_cap;
+ u8 chan_list[P2P_MAX_CHANNELS], channel;
+ u8 num_channels = 0, i;
+
+ if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED)
+ return;
+
+ /* Check whether local driver supports HT40 */
+ if (!wpa_s->hw.modes ||
+ !(wpa_s->hw.modes->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;
+
+ /*
+ * Check whether AP uses regulatory triplet or channel triplet in
+ * country info. Right now the operating class of the BSS channel
+ * width trigger event is "unknown" (IEEE802.11-2012 10.15.12),
+ * based on the assumption that operating class triplet is not used in
+ * beacon frame. If the First Channel Number/Operating Extension
+ * Identifier octet has a positive integer value of 201 or greater,
+ * then its operating class triplet.
+ *
+ * TODO: If Supported Operating Classes element is present in beacon
+ * frame, have to lookup operating class in Annex E and fill them in
+ * 2040 coex frame.
+ */
+ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY);
+ if (!ie || ie[1] < 6 || (ie[5] > 201))
+ return;
+
+ assoc_band = freq_to_channel(wpa_s->current_bss->freq, &channel);
+ os_memset(chan_list, 0, sizeof(chan_list));
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ /* Skip other band bss */
+ if (freq_to_channel(bss->freq, &channel) != assoc_band)
+ continue;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP);
+ ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0;
+
+ if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) {
+ /* Check whether the channel is already considered */
+ for (i = 0; i < num_channels; i++) {
+ if (channel == chan_list[i])
+ break;
+ }
+ if (i != num_channels)
+ continue;
+
+ chan_list[num_channels++] = channel;
+ }
+ }
+
+ if (num_channels)
+ sme_send_2040_bss_coex(wpa_s, chan_list, num_channels);
+}
+#endif /* CONFIG_SME */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index b25116e..f3fb01f 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -628,6 +628,7 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
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);
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index a5472a0..31f0274 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -25,6 +25,17 @@ struct wps_new_ap_settings {
const char *key_hex;
};
+/**
+ * enum wpas_band - Frequency band
+ * @WPAS_BAND_2GHZ: 2.4 GHz ISM band
+ * @WPAS_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz)
+ */
+enum wpas_band {
+ WPAS_BAND_2GHZ,
+ WPAS_BAND_5GHZ,
+ WPAS_BAND_INVALID
+};
+
int wpas_wps_init(struct wpa_supplicant *wpa_s);
void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
--
1.7.10
More information about the Hostap
mailing list