Add AP mode support for HT 20/40 co-ex Action frame
If a 2.4 GHz band AP receives a 20/40 Coexistence management frame from a connected station with 20/40 BSS Intolerant Channel Report element containing the channel list in which any legacy AP are detected or AP with 40 MHz intolerant bit set in HT Cap IE is detected in the affected range of the BSS, the BSS will be moved from 40 to 20 MHz channel width. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
9c47f6a2a6
commit
587d60d2b7
3 changed files with 123 additions and 0 deletions
|
@ -1647,6 +1647,15 @@ static int handle_action(struct hostapd_data *hapd,
|
|||
#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,
|
||||
|
|
|
@ -14,11 +14,14 @@ struct hostapd_data;
|
|||
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,
|
||||
|
|
|
@ -175,6 +175,117 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
|
|||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue