diff options
Diffstat (limited to 'contrib/wpa/src/ap/hw_features.c')
-rw-r--r-- | contrib/wpa/src/ap/hw_features.c | 169 |
1 files changed, 70 insertions, 99 deletions
diff --git a/contrib/wpa/src/ap/hw_features.c b/contrib/wpa/src/ap/hw_features.c index fc8786d..9d3d990 100644 --- a/contrib/wpa/src/ap/hw_features.c +++ b/contrib/wpa/src/ap/hw_features.c @@ -78,10 +78,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) int i, j; u16 num_modes, flags; struct hostapd_hw_modes *modes; + u8 dfs_domain; if (hostapd_drv_none(hapd)) return -1; - modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags); + modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags, + &dfs_domain); if (modes == NULL) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -91,6 +93,7 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } iface->hw_flags = flags; + iface->dfs_domain = dfs_domain; hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); iface->hw_features = modes; @@ -226,9 +229,6 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) { int pri_chan, sec_chan; - if (!iface->conf->secondary_channel) - return 1; /* HT40 not used */ - pri_chan = iface->conf->channel; sec_chan = pri_chan + iface->conf->secondary_channel * 4; @@ -329,6 +329,10 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface) res = ieee80211n_allowed_ht40_channel_pair(iface); if (!res) { iface->conf->secondary_channel = 0; + iface->conf->vht_oper_centr_freq_seg0_idx = 0; + iface->conf->vht_oper_centr_freq_seg1_idx = 0; + iface->conf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT; + res = 1; wpa_printf(MSG_INFO, "Fallback to 20 MHz"); } @@ -472,8 +476,9 @@ 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 */ + /* Check that HT40 is used and PRI / SEC switch is allowed */ + if (!iface->conf->secondary_channel || iface->conf->no_pri_sec_switch) + return 0; hostapd_set_state(iface, HAPD_IFACE_HT_SCAN); wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling " @@ -619,41 +624,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) #ifdef CONFIG_IEEE80211AC - -static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name) -{ - u32 req_cap = conf & cap; - - /* - * Make sure we support all requested capabilities. - * NOTE: We assume that 'cap' represents a capability mask, - * not a discrete value. - */ - if ((hw & req_cap) != req_cap) { - wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]", - name); - return 0; - } - return 1; -} - - -static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask, - unsigned int shift, - const char *name) -{ - u32 hw_max = hw & mask; - u32 conf_val = conf & mask; - - if (conf_val > hw_max) { - wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)", - name, conf_val >> shift, hw_max >> shift); - return 0; - } - return 1; -} - - static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) { struct hostapd_hw_modes *mode = iface->current_mode; @@ -681,45 +651,7 @@ static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface) } } -#define VHT_CAP_CHECK(cap) \ - do { \ - if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \ - return 0; \ - } while (0) - -#define VHT_CAP_CHECK_MAX(cap) \ - do { \ - if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \ - #cap)) \ - return 0; \ - } while (0) - - VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK); - VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ); - VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ); - VHT_CAP_CHECK(VHT_CAP_RXLDPC); - VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80); - VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160); - VHT_CAP_CHECK(VHT_CAP_TXSTBC); - VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK); - VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE); - VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX); - VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX); - VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE); - VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS); - VHT_CAP_CHECK(VHT_CAP_HTC_VHT); - VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX); - VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB); - VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); - VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); - VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); - -#undef VHT_CAP_CHECK -#undef VHT_CAP_CHECK_MAX - - return 1; + return ieee80211ac_cap_check(hw, conf); } #endif /* CONFIG_IEEE80211AC */ @@ -744,7 +676,8 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface) if (!ieee80211n_supported_ht_capab(iface)) return -1; #ifdef CONFIG_IEEE80211AC - if (!ieee80211ac_supported_vht_capab(iface)) + if (iface->conf->ieee80211ac && + !ieee80211ac_supported_vht_capab(iface)) return -1; #endif /* CONFIG_IEEE80211AC */ ret = ieee80211n_check_40mhz(iface); @@ -761,42 +694,66 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface) static int hostapd_is_usable_chan(struct hostapd_iface *iface, int channel, int primary) { - int i; struct hostapd_channel_data *chan; if (!iface->current_mode) return 0; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->chan != channel) - continue; - - if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) - return 1; + chan = hw_get_channel_chan(iface->current_mode, channel, NULL); + if (!chan) + return 0; - wpa_printf(MSG_DEBUG, - "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s", - primary ? "" : "Configured HT40 secondary ", - i, chan->chan, chan->flag, - chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", - chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); - } + if ((primary && chan_pri_allowed(chan)) || + (!primary && !(chan->flag & HOSTAPD_CHAN_DISABLED))) + return 1; + wpa_printf(MSG_INFO, + "Channel %d (%s) not allowed for AP mode, flags: 0x%x%s%s", + channel, primary ? "primary" : "secondary", + chan->flag, + chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", + chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); return 0; } static int hostapd_is_usable_chans(struct hostapd_iface *iface) { + int secondary_chan; + struct hostapd_channel_data *pri_chan; + + pri_chan = hw_get_channel_chan(iface->current_mode, + iface->conf->channel, NULL); + if (!pri_chan) + return 0; + if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1)) return 0; if (!iface->conf->secondary_channel) return 1; - return hostapd_is_usable_chan(iface, iface->conf->channel + - iface->conf->secondary_channel * 4, 0); + if (!iface->conf->ht40_plus_minus_allowed) + return hostapd_is_usable_chan( + iface, iface->conf->channel + + iface->conf->secondary_channel * 4, 0); + + /* Both HT40+ and HT40- are set, pick a valid secondary channel */ + secondary_chan = iface->conf->channel + 4; + if (hostapd_is_usable_chan(iface, secondary_chan, 0) && + (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) { + iface->conf->secondary_channel = 1; + return 1; + } + + secondary_chan = iface->conf->channel - 4; + if (hostapd_is_usable_chan(iface, secondary_chan, 0) && + (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) { + iface->conf->secondary_channel = -1; + return 1; + } + + return 0; } @@ -976,5 +933,19 @@ int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) { - return hw_get_chan(hapd->iface->current_mode, freq); + int i, channel; + struct hostapd_hw_modes *mode; + + channel = hw_get_chan(hapd->iface->current_mode, freq); + if (channel) + return channel; + /* Check other available modes since the channel list for the current + * mode did not include the specified frequency. */ + for (i = 0; i < hapd->iface->num_hw_features; i++) { + mode = &hapd->iface->hw_features[i]; + channel = hw_get_chan(mode, freq); + if (channel) + return channel; + } + return 0; } |