Cumulative patch from commit c0333c8dd59b9e254d3fc725c984b1c0cd3d496a
c0333c8 Check rx_mgmt::frame more consistently against NULL
d6c6b1f Make sta NULL-check easier for static analyzers
0bceb8d Make dl_list_first() and dl_list_last() uses easier for static analyzers
5f693cb WPS HTTP: Remove unused assignment
ee4fefc Remove duplicated variable zeroing
4a9d0eb Make PMKID check easier for static analyzers
06df2aa Remove floating constant suffix 'd' from test coee
9670f87 ACS: Clean up ifdef CONFIG_ACS to avoid unreachable code
ece88f7 Make last_scan_res update easier for static analyzers
d06e9ac P2P: Verify operating channel validity for NFC connection handover
13a524a nl80211: Remove unnecessary wpa_driver_nl80211_set_freq() wrapper
e87ef75 nl80211: Add support for changing AP mode channel bandwidth
3057518 Sync with mac80211-next.git nl80211.h
5f0bca7 Retry initial 20/40 MHz co-ex scan if the driver is busy
587d60d Add AP mode support for HT 20/40 co-ex Action frame
9c47f6a hostapd: Extend support for HT 20/40 coexistence feature
196c9c7 Make channel parameters available in set_ap() driver operation
b7a6702 Indicate disconnection event on interface disabled
b89962b Fix wpa_config_read() with existing config block
27b4187 WPS: Print setsockopt() failure in debug log
52cb207 trace: Replace demangle.h with internal defines
0e80ea2 nl80211: Fix some coding style issues
a26582c Make qca-vendor.h independent of other header files
4a64d5a nl80211: Allocate QCA vendor subcmd for extended statistics
Change-Id: Ibabee77b2b87f04f99d6b1ca0f1ac741cb9222c0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 0a143d3..9680817 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -174,11 +174,11 @@
conf->ap_table_expiration_time = 60;
#ifdef CONFIG_TESTING_OPTIONS
- conf->ignore_probe_probability = 0.0d;
- conf->ignore_auth_probability = 0.0d;
- conf->ignore_assoc_probability = 0.0d;
- conf->ignore_reassoc_probability = 0.0d;
- conf->corrupt_gtk_rekey_mic_probability = 0.0d;
+ conf->ignore_probe_probability = 0.0;
+ conf->ignore_auth_probability = 0.0;
+ conf->ignore_assoc_probability = 0.0;
+ conf->ignore_reassoc_probability = 0.0;
+ conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 56df318..27525dc 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -645,7 +645,7 @@
* with AP configuration */
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->iconf->ignore_probe_probability > 0.0d &&
+ if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring probe request from " MACSTR,
@@ -951,6 +951,9 @@
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct wpa_driver_ap_params params;
+ struct hostapd_freq_params freq;
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
@@ -972,6 +975,17 @@
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
+ if (iface->current_mode &&
+ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+ iconf->channel, iconf->ieee80211n,
+ iconf->ieee80211ac,
+ iconf->secondary_channel,
+ iconf->vht_oper_chwidth,
+ iconf->vht_oper_centr_freq_seg0_idx,
+ iconf->vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab) == 0)
+ params.freq = &freq;
+
res = hostapd_drv_set_ap(hapd, ¶ms);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
if (res)
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9760933..ccbbab5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -405,6 +405,7 @@
"num_sta_ht_no_gf=%d\n"
"num_sta_no_ht=%d\n"
"num_sta_ht_20_mhz=%d\n"
+ "num_sta_ht40_intolerant=%d\n"
"olbc_ht=%d\n"
"ht_op_mode=0x%x\n",
hostapd_state_text(iface->state),
@@ -417,6 +418,7 @@
iface->num_sta_ht_no_gf,
iface->num_sta_no_ht,
iface->num_sta_ht_20mhz,
+ iface->num_sta_ht40_intolerant,
iface->olbc_ht,
iface->ht_op_mode);
if (ret < 0 || (size_t) ret >= buflen - len)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a8c24eb..fb095ef 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "radius/radius.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
@@ -30,6 +31,7 @@
#include "ap_config.h"
#include "hw_features.h"
#include "dfs.h"
+#include "beacon.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -121,6 +123,24 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities) &&
+ (hapd->iface->conf->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ 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)
+ ht40_intolerant_add(hapd->iface, sta);
+ }
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
+
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
if (elems.ext_capab[4] & 0x01)
@@ -981,6 +1001,8 @@
break;
#endif /* NEED_AP_MLME */
case EVENT_RX_MGMT:
+ if (!data->rx_mgmt.frame)
+ break;
#ifdef NEED_AP_MLME
if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 614a5bf..391d774 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -33,6 +33,7 @@
#include "p2p_hostapd.h"
#include "gas_serv.h"
#include "dfs.h"
+#include "ieee802_11.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -1352,6 +1353,12 @@
if (iface == NULL)
return;
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 090544d..bd85c54 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -327,6 +327,9 @@
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
+ /* Number of HT40 intolerant stations */
+ int num_sta_ht40_intolerant;
+
/* Overlapping BSS information */
int olbc_ht;
@@ -351,11 +354,16 @@
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
+ /* Latched with the actual secondary channel information and will be
+ * used while juggling between HT20 and HT40 modes. */
+ int secondary_ch;
+
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
#endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface);
+ int num_ht40_scan_tries;
};
/* hostapd.c */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d47a366..b361834 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -19,6 +19,8 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "acs.h"
+#include "ieee802_11.h"
+#include "beacon.h"
#include "hw_features.h"
@@ -414,6 +416,7 @@
int pri = bss->freq;
int sec = pri;
int sec_chan, pri_chan;
+ struct ieee802_11_elems elems;
ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
@@ -445,7 +448,23 @@
}
}
- /* TODO: 40 MHz intolerant */
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+ 0);
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_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;
@@ -475,6 +494,7 @@
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
wpa_scan_results_free(scan_res);
+ iface->secondary_ch = iface->conf->secondary_channel;
if (!oper40) {
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
"channel pri=%d sec=%d based on overlapping BSSes",
@@ -482,9 +502,21 @@
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
+ /*
+ * TODO: Could consider scheduling another scan to check
+ * if channel width can be changed if no coex reports
+ * are received from associating stations.
+ */
+ }
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
+ if (!res) {
+ iface->conf->secondary_channel = 0;
+ wpa_printf(MSG_INFO, "Fallback to 20 MHz");
+ }
+
hostapd_setup_interface_complete(iface, !res);
}
@@ -570,9 +602,55 @@
}
+static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
+{
+#define HT2040_COEX_SCAN_RETRY 15
+ struct hostapd_iface *iface = eloop_data;
+ struct wpa_driver_scan_params params;
+ int ret;
+
+ os_memset(¶ms, 0, sizeof(params));
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, ¶ms);
+ else
+ ieee80211n_scan_channels_5g(iface, ¶ms);
+
+ ret = hostapd_driver_scan(iface->bss[0], ¶ms);
+ iface->num_ht40_scan_tries++;
+ os_free(params.freqs);
+
+ if (ret == -EBUSY &&
+ iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
+ ret, strerror(-ret), iface->num_ht40_scan_tries);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return;
+ }
+
+ if (ret == 0) {
+ iface->scan_cb = ieee80211n_check_scan;
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to request a scan in device, bringing up in HT20 mode");
+ iface->conf->secondary_channel = 0;
+ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ hostapd_setup_interface_complete(iface, 0);
+}
+
+
+void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+}
+
+
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
+ int ret;
if (!iface->conf->secondary_channel)
return 0; /* HT40 not used */
@@ -585,13 +663,26 @@
ieee80211n_scan_channels_2g4(iface, ¶ms);
else
ieee80211n_scan_channels_5g(iface, ¶ms);
- if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
- wpa_printf(MSG_ERROR, "Failed to request a scan of "
- "neighboring BSSes");
- os_free(params.freqs);
+
+ ret = hostapd_driver_scan(iface->bss[0], ¶ms);
+ os_free(params.freqs);
+
+ if (ret == -EBUSY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
+ ret, strerror(-ret));
+ iface->num_ht40_scan_tries = 1;
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return 1;
+ }
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s)",
+ ret, strerror(-ret));
return -1;
}
- os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 783ae5e..0f67ab8 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -23,6 +23,7 @@
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
+void hostapd_stop_setup_timers(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -61,6 +62,10 @@
return 0;
}
+static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 14fb567..ca8db8f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -62,7 +62,6 @@
}
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
i++) {
count++;
@@ -105,7 +104,6 @@
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
i++) {
count++;
@@ -565,7 +563,7 @@
}
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->iconf->ignore_auth_probability > 0.0d &&
+ if (hapd->iconf->ignore_auth_probability > 0.0 &&
drand48() < hapd->iconf->ignore_auth_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring auth frame from " MACSTR,
@@ -1291,7 +1289,7 @@
#ifdef CONFIG_TESTING_OPTIONS
if (reassoc) {
- if (hapd->iconf->ignore_reassoc_probability > 0.0d &&
+ if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
drand48() < hapd->iconf->ignore_reassoc_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring reassoc request from "
@@ -1299,7 +1297,7 @@
return;
}
} else {
- if (hapd->iconf->ignore_assoc_probability > 0.0d &&
+ if (hapd->iconf->ignore_assoc_probability > 0.0 &&
drand48() < hapd->iconf->ignore_assoc_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring assoc request from "
@@ -1628,7 +1626,8 @@
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
- if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+ if (!sta ||
+ wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
return 1;
@@ -1647,6 +1646,15 @@
#endif /* CONFIG_WNM */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
+#ifdef CONFIG_IEEE80211N
+ if (mgmt->u.action.u.public_action.action ==
+ WLAN_PA_20_40_BSS_COEX) {
+ wpa_printf(MSG_DEBUG,
+ "HT20/40 coex mgmt frame received from STA "
+ MACSTR, MAC2STR(mgmt->sa));
+ hostapd_2040_coex_action(hapd, mgmt, len);
+ }
+#endif /* CONFIG_IEEE80211N */
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
(u8 *) mgmt, len,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 809b4ca..cf0d3f2 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,11 +14,14 @@
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
+struct ieee80211_mgmt;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
u16 stype, int ok);
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@@ -39,6 +42,7 @@
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
+void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
@@ -59,6 +63,8 @@
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 1d64748..c0a7cd4 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -10,12 +10,15 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
+#include "hw_features.h"
+#include "ap_drv_ops.h"
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
@@ -172,6 +175,117 @@
}
+static int is_40_allowed(struct hostapd_iface *iface, int channel)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ int pri = 2407 + 5 * channel;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return 1;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+
+ if (iface->conf->secondary_channel > 0)
+ sec_freq = pri_freq + 20;
+ else
+ sec_freq = pri_freq - 20;
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ if ((pri < affected_start || pri > affected_end))
+ return 1; /* not within affected channel range */
+
+ wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+ wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri);
+ return 0;
+}
+
+
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct ieee80211_2040_bss_coex_ie *bc_ie;
+ struct ieee80211_2040_intol_chan_report *ic_report;
+ int is_ht_allowed = 1;
+ int i;
+ const u8 *data = (const u8 *) &mgmt->u.action.u.public_action.action;
+ size_t hdr_len;
+
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
+ mgmt->u.action.u.public_action.action);
+
+ if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
+
+ hdr_len = data - (u8 *) mgmt;
+ if (hdr_len > len)
+ return;
+ data++;
+
+ bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0];
+ ic_report = (struct ieee80211_2040_intol_chan_report *)
+ (&data[0] + sizeof(*bc_ie));
+
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20 MHz BSS width request bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "40 MHz intolerant bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (ic_report &&
+ (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) {
+ /* Go through the channel report to find any BSS there in the
+ * affected channel range */
+ for (i = 0; i < ic_report->length - 1; i++) {
+ if (is_40_allowed(iface, ic_report->variable[i]))
+ continue;
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20_40_INTOLERANT channel %d reported",
+ ic_report->variable[i]);
+ is_ht_allowed = 0;
+ break;
+ }
+ }
+
+ if (!is_ht_allowed &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ if (iface->conf->secondary_channel) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Switching to 20 MHz operation");
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+ if (!iface->num_sta_ht40_intolerant) {
+ unsigned int delay_time;
+ delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
+ NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ hapd->iface, NULL);
+ }
+ }
+}
+
+
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
@@ -200,6 +314,52 @@
}
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return;
+
+ wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
+ " in Association Request", MAC2STR(sta->addr));
+
+ if (sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 1;
+ iface->num_sta_ht40_intolerant++;
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+
+ if (iface->conf->secondary_channel &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+}
+
+
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (!sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 0;
+ iface->num_sta_ht40_intolerant--;
+
+ if (iface->num_sta_ht40_intolerant == 0 &&
+ (iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ wpa_printf(MSG_DEBUG,
+ "HT: Start 20->40 MHz transition timer (%d seconds)",
+ delay_time);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ iface, NULL);
+ }
+}
+
+
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
u16 ht_capab;
@@ -227,6 +387,9 @@
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
+
+ if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT)
+ ht40_intolerant_add(hapd->iface, sta);
}
@@ -288,3 +451,14 @@
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
}
+
+
+void ap_ht2040_timeout(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+
+ wpa_printf(MSG_INFO, "Switching to 40 MHz operation");
+
+ iface->conf->secondary_channel = iface->secondary_ch;
+ ieee802_11_set_beacons(iface);
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f5417de..60f0768 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -206,6 +206,10 @@
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_IEEE80211N
+ ht40_intolerant_remove(hapd->iface, sta);
+#endif /* CONFIG_IEEE80211N */
+
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 2dbdeb1..03db98f 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -54,6 +54,7 @@
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
+ unsigned int ht40_intolerant_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
unsigned int qos_map_enabled:1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 77e7858..d212610 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1421,7 +1421,7 @@
key->key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+ wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
drand48() <
wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index e957c6e..1e4defc 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -675,7 +675,7 @@
break;
}
}
- if (sm->pmksa) {
+ if (sm->pmksa && pmkid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",