diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-02-07 05:47:44 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-02-15 03:41:30 -0500 |
commit | e1a0c6b3a4b27ed5f21291d0bbee2167ec201ef5 (patch) | |
tree | 18e5c9bd022ea469e7350a52ca67ce505a7608e6 | |
parent | 4a34215ef7487b1cbd783e7cc485eb03de893bd0 (diff) |
mac80211: stop toggling IEEE80211_HT_CAP_SUP_WIDTH_20_40
For VHT, many more bandwidth changes are possible. As a first
step, stop toggling the IEEE80211_HT_CAP_SUP_WIDTH_20_40 flag
in the HT capabilities and instead introduce a bandwidth field
indicating the currently usable bandwidth to transmit to the
station. Of course, make all drivers use it.
To achieve this, make ieee80211_ht_cap_ie_to_sta_ht_cap() get
the station as an argument, rather than the new capabilities,
so it can set up the new bandwidth field.
If the station is a VHT station and VHT bandwidth is in use,
also set the bandwidth accordingly.
Doing this allows us to get rid of the supports_40mhz flag as
the HT capabilities now reflect the true capability instead of
the current setting.
While at it, also fix ieee80211_ht_cap_ie_to_sta_ht_cap() to not
ignore HT cap overrides when MCS TX isn't supported (not that it
really happens...)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
27 files changed, 184 insertions, 158 deletions
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 714558d1ba78..54150b6a39ae 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c | |||
@@ -1204,7 +1204,7 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta) | |||
1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; | 1204 | caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG; |
1205 | else if (sta->ht_cap.mcs.rx_mask[1]) | 1205 | else if (sta->ht_cap.mcs.rx_mask[1]) |
1206 | caps |= WLAN_RC_DS_FLAG; | 1206 | caps |= WLAN_RC_DS_FLAG; |
1207 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { | 1207 | if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) { |
1208 | caps |= WLAN_RC_40_FLAG; | 1208 | caps |= WLAN_RC_40_FLAG; |
1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | 1209 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) |
1210 | caps |= WLAN_RC_SGI_FLAG; | 1210 | caps |= WLAN_RC_SGI_FLAG; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f41ae79e6bc0..41ec27cb6efe 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h | |||
@@ -338,7 +338,7 @@ int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | |||
338 | 338 | ||
339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 339 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
340 | struct iwl_rxon_context *ctx, | 340 | struct iwl_rxon_context *ctx, |
341 | struct ieee80211_sta_ht_cap *ht_cap); | 341 | struct ieee80211_sta *sta); |
342 | 342 | ||
343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) | 343 | static inline int iwl_sta_id(struct ieee80211_sta *sta) |
344 | { | 344 | { |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index a131227c49e9..b25de02964f9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c | |||
@@ -1305,7 +1305,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, | |||
1305 | tbl->max_search = IWL_MAX_SEARCH; | 1305 | tbl->max_search = IWL_MAX_SEARCH; |
1306 | rate_mask = lq_sta->active_mimo2_rate; | 1306 | rate_mask = lq_sta->active_mimo2_rate; |
1307 | 1307 | ||
1308 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1308 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1309 | tbl->is_ht40 = 1; | 1309 | tbl->is_ht40 = 1; |
1310 | else | 1310 | else |
1311 | tbl->is_ht40 = 0; | 1311 | tbl->is_ht40 = 0; |
@@ -1361,7 +1361,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, | |||
1361 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1361 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
1362 | rate_mask = lq_sta->active_mimo3_rate; | 1362 | rate_mask = lq_sta->active_mimo3_rate; |
1363 | 1363 | ||
1364 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1364 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1365 | tbl->is_ht40 = 1; | 1365 | tbl->is_ht40 = 1; |
1366 | else | 1366 | else |
1367 | tbl->is_ht40 = 0; | 1367 | tbl->is_ht40 = 0; |
@@ -1410,7 +1410,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, | |||
1410 | tbl->max_search = IWL_MAX_SEARCH; | 1410 | tbl->max_search = IWL_MAX_SEARCH; |
1411 | rate_mask = lq_sta->active_siso_rate; | 1411 | rate_mask = lq_sta->active_siso_rate; |
1412 | 1412 | ||
1413 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 1413 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
1414 | tbl->is_ht40 = 1; | 1414 | tbl->is_ht40 = 1; |
1415 | else | 1415 | else |
1416 | tbl->is_ht40 = 0; | 1416 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index ab768045696b..6deab38c7aee 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -173,7 +173,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
173 | 173 | ||
174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | 174 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, |
175 | struct iwl_rxon_context *ctx, | 175 | struct iwl_rxon_context *ctx, |
176 | struct ieee80211_sta_ht_cap *ht_cap) | 176 | struct ieee80211_sta *sta) |
177 | { | 177 | { |
178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | 178 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) |
179 | return false; | 179 | return false; |
@@ -183,20 +183,11 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | |||
183 | return false; | 183 | return false; |
184 | #endif | 184 | #endif |
185 | 185 | ||
186 | /* | 186 | /* special case for RXON */ |
187 | * Remainder of this function checks ht_cap, but if it's | 187 | if (!sta) |
188 | * NULL then we can do HT40 (special case for RXON) | ||
189 | */ | ||
190 | if (!ht_cap) | ||
191 | return true; | 188 | return true; |
192 | 189 | ||
193 | if (!ht_cap->ht_supported) | 190 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
194 | return false; | ||
195 | |||
196 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
197 | return false; | ||
198 | |||
199 | return true; | ||
200 | } | 191 | } |
201 | 192 | ||
202 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | 193 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, |
@@ -246,7 +237,7 @@ static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | |||
246 | *flags |= cpu_to_le32( | 237 | *flags |= cpu_to_le32( |
247 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | 238 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); |
248 | 239 | ||
249 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | 240 | if (iwl_is_ht40_tx_allowed(priv, ctx, sta)) |
250 | *flags |= STA_FLG_HT40_EN_MSK; | 241 | *flags |= STA_FLG_HT40_EN_MSK; |
251 | } | 242 | } |
252 | 243 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 60a4291ca221..8ba36e5e4b67 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c | |||
@@ -1209,23 +1209,9 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm, | |||
1209 | return new_rate; | 1209 | return new_rate; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | static bool iwl_is_ht40_tx_allowed(struct iwl_mvm *mvm, | 1212 | static bool iwl_is_ht40_tx_allowed(struct ieee80211_sta *sta) |
1213 | struct ieee80211_sta_ht_cap *ht_cap) | ||
1214 | { | 1213 | { |
1215 | /* | 1214 | return sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
1216 | * Remainder of this function checks ht_cap, but if it's | ||
1217 | * NULL then we can do HT40 (special case for RXON) | ||
1218 | */ | ||
1219 | if (!ht_cap) | ||
1220 | return true; | ||
1221 | |||
1222 | if (!ht_cap->ht_supported) | ||
1223 | return false; | ||
1224 | |||
1225 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
1226 | return false; | ||
1227 | |||
1228 | return true; | ||
1229 | } | 1215 | } |
1230 | 1216 | ||
1231 | /* | 1217 | /* |
@@ -1258,7 +1244,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm, | |||
1258 | tbl->max_search = IWL_MAX_SEARCH; | 1244 | tbl->max_search = IWL_MAX_SEARCH; |
1259 | rate_mask = lq_sta->active_mimo2_rate; | 1245 | rate_mask = lq_sta->active_mimo2_rate; |
1260 | 1246 | ||
1261 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1247 | if (iwl_is_ht40_tx_allowed(sta)) |
1262 | tbl->is_ht40 = 1; | 1248 | tbl->is_ht40 = 1; |
1263 | else | 1249 | else |
1264 | tbl->is_ht40 = 0; | 1250 | tbl->is_ht40 = 0; |
@@ -1311,7 +1297,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm, | |||
1311 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; | 1297 | tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH; |
1312 | rate_mask = lq_sta->active_mimo3_rate; | 1298 | rate_mask = lq_sta->active_mimo3_rate; |
1313 | 1299 | ||
1314 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1300 | if (iwl_is_ht40_tx_allowed(sta)) |
1315 | tbl->is_ht40 = 1; | 1301 | tbl->is_ht40 = 1; |
1316 | else | 1302 | else |
1317 | tbl->is_ht40 = 0; | 1303 | tbl->is_ht40 = 0; |
@@ -1356,7 +1342,7 @@ static int rs_switch_to_siso(struct iwl_mvm *mvm, | |||
1356 | tbl->max_search = IWL_MAX_SEARCH; | 1342 | tbl->max_search = IWL_MAX_SEARCH; |
1357 | rate_mask = lq_sta->active_siso_rate; | 1343 | rate_mask = lq_sta->active_siso_rate; |
1358 | 1344 | ||
1359 | if (iwl_is_ht40_tx_allowed(mvm, &sta->ht_cap)) | 1345 | if (iwl_is_ht40_tx_allowed(sta)) |
1360 | tbl->is_ht40 = 1; | 1346 | tbl->is_ht40 = 1; |
1361 | else | 1347 | else |
1362 | tbl->is_ht40 = 0; | 1348 | tbl->is_ht40 = 0; |
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 4494d130b37c..84ea04dab303 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c | |||
@@ -523,8 +523,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw, | |||
523 | if (mac->opmode == NL80211_IFTYPE_STATION) | 523 | if (mac->opmode == NL80211_IFTYPE_STATION) |
524 | bw_40 = mac->bw_40; | 524 | bw_40 = mac->bw_40; |
525 | else if (mac->opmode == NL80211_IFTYPE_AP || | 525 | else if (mac->opmode == NL80211_IFTYPE_AP || |
526 | mac->opmode == NL80211_IFTYPE_ADHOC) | 526 | mac->opmode == NL80211_IFTYPE_ADHOC) |
527 | bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 527 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
528 | 528 | ||
529 | if (bw_40 && sgi_40) | 529 | if (bw_40 && sgi_40) |
530 | tcb_desc->use_shortgi = true; | 530 | tcb_desc->use_shortgi = true; |
@@ -634,8 +634,7 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, | |||
634 | return; | 634 | return; |
635 | if (mac->opmode == NL80211_IFTYPE_AP || | 635 | if (mac->opmode == NL80211_IFTYPE_AP || |
636 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 636 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
637 | if (!(sta->ht_cap.ht_supported) || | 637 | if (sta->bandwidth == IEEE80211_STA_RX_BW_20) |
638 | !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
639 | return; | 638 | return; |
640 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { | 639 | } else if (mac->opmode == NL80211_IFTYPE_STATION) { |
641 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) | 640 | if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) |
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 204f46c4510d..c12a866e1261 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
@@ -116,9 +116,8 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | |||
116 | if (txrc->short_preamble) | 116 | if (txrc->short_preamble) |
117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | 117 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; |
118 | if (mac->opmode == NL80211_IFTYPE_AP || | 118 | if (mac->opmode == NL80211_IFTYPE_AP || |
119 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 119 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
120 | if (sta && (sta->ht_cap.cap & | 120 | if (sta && (sta->bandwidth >= IEEE80211_STA_RX_BW_40)) |
121 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
122 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | 121 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
123 | } else { | 122 | } else { |
124 | if (mac->bw_40) | 123 | if (mac->bw_40) |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index d1f34f6ffbdf..1b65db7fd651 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c | |||
@@ -1846,9 +1846,9 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1846 | struct rtl_sta_info *sta_entry = NULL; | 1846 | struct rtl_sta_info *sta_entry = NULL; |
1847 | u32 ratr_bitmap; | 1847 | u32 ratr_bitmap; |
1848 | u8 ratr_index; | 1848 | u8 ratr_index; |
1849 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1849 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1850 | ? 1 : 0; | 1850 | u8 curshortgi_40mhz = curtxbw_40mhz && |
1851 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1851 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1852 | 1 : 0; | 1852 | 1 : 0; |
1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1853 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
1854 | 1 : 0; | 1854 | 1 : 0; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index da0e9022a99a..b9b1a6e0b16e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | |||
@@ -626,8 +626,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, | |||
626 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 626 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
627 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 627 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
628 | if (sta) | 628 | if (sta) |
629 | bw_40 = sta->ht_cap.cap & | 629 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
630 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
631 | } | 630 | } |
632 | 631 | ||
633 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 632 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index f4051f4f0390..aa5b42521bb4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c | |||
@@ -1970,8 +1970,7 @@ static void rtl92de_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1970 | struct rtl_sta_info *sta_entry = NULL; | 1970 | struct rtl_sta_info *sta_entry = NULL; |
1971 | u32 ratr_bitmap; | 1971 | u32 ratr_bitmap; |
1972 | u8 ratr_index; | 1972 | u8 ratr_index; |
1973 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1973 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1974 | ? 1 : 0; | ||
1975 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1974 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1976 | 1 : 0; | 1975 | 1 : 0; |
1977 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1976 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index cdb570ffb4b5..941080e03c06 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c | |||
@@ -574,8 +574,7 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, | |||
574 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 574 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
575 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 575 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
576 | if (sta) | 576 | if (sta) |
577 | bw_40 = sta->ht_cap.cap & | 577 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
578 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
579 | } | 578 | } |
580 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 579 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
581 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); | 580 | rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc); |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index 28526a7361f5..084e7773bce2 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c | |||
@@ -2085,8 +2085,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
2085 | struct rtl_sta_info *sta_entry = NULL; | 2085 | struct rtl_sta_info *sta_entry = NULL; |
2086 | u32 ratr_bitmap; | 2086 | u32 ratr_bitmap; |
2087 | u8 ratr_index = 0; | 2087 | u8 ratr_index = 0; |
2088 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 2088 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
2089 | ? 1 : 0; | ||
2090 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 2089 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
2091 | 1 : 0; | 2090 | 1 : 0; |
2092 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 2091 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index f8431a3c2c9d..7b0a2e75b8b8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c | |||
@@ -621,8 +621,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, | |||
621 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 621 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
622 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 622 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
623 | if (sta) | 623 | if (sta) |
624 | bw_40 = sta->ht_cap.cap & | 624 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
625 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
626 | } | 625 | } |
627 | 626 | ||
628 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 627 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c index 149804816ac4..9a0c71c2e15e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c | |||
@@ -1866,8 +1866,7 @@ static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
1866 | struct rtl_sta_info *sta_entry = NULL; | 1866 | struct rtl_sta_info *sta_entry = NULL; |
1867 | u32 ratr_bitmap; | 1867 | u32 ratr_bitmap; |
1868 | u8 ratr_index; | 1868 | u8 ratr_index; |
1869 | u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1869 | u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0; |
1870 | ? 1 : 0; | ||
1871 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | 1870 | u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? |
1872 | 1 : 0; | 1871 | 1 : 0; |
1873 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? | 1872 | u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? |
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c index b1fd2b328abf..ac081297db50 100644 --- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | |||
@@ -395,8 +395,7 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw, | |||
395 | } else if (mac->opmode == NL80211_IFTYPE_AP || | 395 | } else if (mac->opmode == NL80211_IFTYPE_AP || |
396 | mac->opmode == NL80211_IFTYPE_ADHOC) { | 396 | mac->opmode == NL80211_IFTYPE_ADHOC) { |
397 | if (sta) | 397 | if (sta) |
398 | bw_40 = sta->ht_cap.cap & | 398 | bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
399 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
400 | } | 399 | } |
401 | 400 | ||
402 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; | 401 | seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index a10b7a7a215a..da3ef1b10a9c 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c | |||
@@ -1374,7 +1374,7 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl, | |||
1374 | struct ieee80211_sta *sta, | 1374 | struct ieee80211_sta *sta, |
1375 | u32 changed) | 1375 | u32 changed) |
1376 | { | 1376 | { |
1377 | bool wide = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 1377 | bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40; |
1378 | 1378 | ||
1379 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); | 1379 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide); |
1380 | 1380 | ||
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7241962f9f13..1e3b4f730397 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1197,6 +1197,24 @@ enum ieee80211_sta_state { | |||
1197 | }; | 1197 | }; |
1198 | 1198 | ||
1199 | /** | 1199 | /** |
1200 | * enum ieee80211_sta_rx_bandwidth - station RX bandwidth | ||
1201 | * @IEEE80211_STA_RX_BW_20: station can only receive 20 MHz | ||
1202 | * @IEEE80211_STA_RX_BW_40: station can receive up to 40 MHz | ||
1203 | * @IEEE80211_STA_RX_BW_80: station can receive up to 80 MHz | ||
1204 | * @IEEE80211_STA_RX_BW_160: station can receive up to 160 MHz | ||
1205 | * (including 80+80 MHz) | ||
1206 | * | ||
1207 | * Implementation note: 20 must be zero to be initialized | ||
1208 | * correctly, the values must be sorted. | ||
1209 | */ | ||
1210 | enum ieee80211_sta_rx_bandwidth { | ||
1211 | IEEE80211_STA_RX_BW_20 = 0, | ||
1212 | IEEE80211_STA_RX_BW_40, | ||
1213 | IEEE80211_STA_RX_BW_80, | ||
1214 | IEEE80211_STA_RX_BW_160, | ||
1215 | }; | ||
1216 | |||
1217 | /** | ||
1200 | * struct ieee80211_sta - station table entry | 1218 | * struct ieee80211_sta - station table entry |
1201 | * | 1219 | * |
1202 | * A station table entry represents a station we are possibly | 1220 | * A station table entry represents a station we are possibly |
@@ -1218,6 +1236,7 @@ enum ieee80211_sta_state { | |||
1218 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid | 1236 | * @uapsd_queues: bitmap of queues configured for uapsd. Only valid |
1219 | * if wme is supported. | 1237 | * if wme is supported. |
1220 | * @max_sp: max Service Period. Only valid if wme is supported. | 1238 | * @max_sp: max Service Period. Only valid if wme is supported. |
1239 | * @bandwidth: current bandwidth the station can receive with | ||
1221 | */ | 1240 | */ |
1222 | struct ieee80211_sta { | 1241 | struct ieee80211_sta { |
1223 | u32 supp_rates[IEEE80211_NUM_BANDS]; | 1242 | u32 supp_rates[IEEE80211_NUM_BANDS]; |
@@ -1228,6 +1247,7 @@ struct ieee80211_sta { | |||
1228 | bool wme; | 1247 | bool wme; |
1229 | u8 uapsd_queues; | 1248 | u8 uapsd_queues; |
1230 | u8 max_sp; | 1249 | u8 max_sp; |
1250 | enum ieee80211_sta_rx_bandwidth bandwidth; | ||
1231 | 1251 | ||
1232 | /* must be last */ | 1252 | /* must be last */ |
1233 | u8 drv_priv[0] __aligned(sizeof(void *)); | 1253 | u8 drv_priv[0] __aligned(sizeof(void *)); |
@@ -2086,7 +2106,9 @@ enum ieee80211_frame_release_type { | |||
2086 | * enum ieee80211_rate_control_changed - flags to indicate what changed | 2106 | * enum ieee80211_rate_control_changed - flags to indicate what changed |
2087 | * | 2107 | * |
2088 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit | 2108 | * @IEEE80211_RC_BW_CHANGED: The bandwidth that can be used to transmit |
2089 | * to this station changed. | 2109 | * to this station changed. The actual bandwidth is in the station |
2110 | * information -- for HT20/40 the IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
2111 | * flag changes, for HT and VHT the bandwidth field changes. | ||
2090 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. | 2112 | * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed. |
2091 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer | 2113 | * @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer |
2092 | * changed (in IBSS mode) due to discovering more information about | 2114 | * changed (in IBSS mode) due to discovering more information about |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 9c9496d01120..c3869ba42343 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1252,8 +1252,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, | |||
1252 | 1252 | ||
1253 | if (params->ht_capa) | 1253 | if (params->ht_capa) |
1254 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 1254 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1255 | params->ht_capa, | 1255 | params->ht_capa, sta); |
1256 | &sta->sta.ht_cap); | ||
1257 | 1256 | ||
1258 | if (params->vht_capa) | 1257 | if (params->vht_capa) |
1259 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 1258 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 9e7560becbbb..a64b4f0d373f 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -37,6 +37,9 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); | 37 | u8 *smask = (u8 *)(&sdata->u.mgd.ht_capa_mask.mcs.rx_mask); |
38 | int i; | 38 | int i; |
39 | 39 | ||
40 | if (!ht_cap->ht_supported) | ||
41 | return; | ||
42 | |||
40 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { | 43 | if (sdata->vif.type != NL80211_IFTYPE_STATION) { |
41 | /* AP interfaces call this code when adding new stations, | 44 | /* AP interfaces call this code when adding new stations, |
42 | * so just silently ignore non station interfaces. | 45 | * so just silently ignore non station interfaces. |
@@ -89,22 +92,23 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | |||
89 | } | 92 | } |
90 | 93 | ||
91 | 94 | ||
92 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 95 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
93 | struct ieee80211_supported_band *sband, | 96 | struct ieee80211_supported_band *sband, |
94 | struct ieee80211_ht_cap *ht_cap_ie, | 97 | struct ieee80211_ht_cap *ht_cap_ie, |
95 | struct ieee80211_sta_ht_cap *ht_cap) | 98 | struct sta_info *sta) |
96 | { | 99 | { |
100 | struct ieee80211_sta_ht_cap ht_cap; | ||
97 | u8 ampdu_info, tx_mcs_set_cap; | 101 | u8 ampdu_info, tx_mcs_set_cap; |
98 | int i, max_tx_streams; | 102 | int i, max_tx_streams; |
103 | bool changed; | ||
104 | enum ieee80211_sta_rx_bandwidth bw; | ||
99 | 105 | ||
100 | BUG_ON(!ht_cap); | 106 | memset(&ht_cap, 0, sizeof(ht_cap)); |
101 | |||
102 | memset(ht_cap, 0, sizeof(*ht_cap)); | ||
103 | 107 | ||
104 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) | 108 | if (!ht_cap_ie || !sband->ht_cap.ht_supported) |
105 | return; | 109 | goto apply; |
106 | 110 | ||
107 | ht_cap->ht_supported = true; | 111 | ht_cap.ht_supported = true; |
108 | 112 | ||
109 | /* | 113 | /* |
110 | * The bits listed in this expression should be | 114 | * The bits listed in this expression should be |
@@ -112,7 +116,7 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
112 | * advertises more then we can't use those thus | 116 | * advertises more then we can't use those thus |
113 | * we mask them out. | 117 | * we mask them out. |
114 | */ | 118 | */ |
115 | ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & | 119 | ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & |
116 | (sband->ht_cap.cap | | 120 | (sband->ht_cap.cap | |
117 | ~(IEEE80211_HT_CAP_LDPC_CODING | | 121 | ~(IEEE80211_HT_CAP_LDPC_CODING | |
118 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | 122 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | |
@@ -121,44 +125,30 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
121 | IEEE80211_HT_CAP_SGI_40 | | 125 | IEEE80211_HT_CAP_SGI_40 | |
122 | IEEE80211_HT_CAP_DSSSCCK40)); | 126 | IEEE80211_HT_CAP_DSSSCCK40)); |
123 | 127 | ||
124 | /* Unset 40 MHz if we're not using a 40 MHz channel */ | ||
125 | switch (sdata->vif.bss_conf.chandef.width) { | ||
126 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
127 | case NL80211_CHAN_WIDTH_20: | ||
128 | ht_cap->cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
129 | ht_cap->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
130 | break; | ||
131 | case NL80211_CHAN_WIDTH_40: | ||
132 | case NL80211_CHAN_WIDTH_80: | ||
133 | case NL80211_CHAN_WIDTH_80P80: | ||
134 | case NL80211_CHAN_WIDTH_160: | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | /* | 128 | /* |
139 | * The STBC bits are asymmetric -- if we don't have | 129 | * The STBC bits are asymmetric -- if we don't have |
140 | * TX then mask out the peer's RX and vice versa. | 130 | * TX then mask out the peer's RX and vice versa. |
141 | */ | 131 | */ |
142 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) | 132 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) |
143 | ht_cap->cap &= ~IEEE80211_HT_CAP_RX_STBC; | 133 | ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; |
144 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) | 134 | if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) |
145 | ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; | 135 | ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; |
146 | 136 | ||
147 | ampdu_info = ht_cap_ie->ampdu_params_info; | 137 | ampdu_info = ht_cap_ie->ampdu_params_info; |
148 | ht_cap->ampdu_factor = | 138 | ht_cap.ampdu_factor = |
149 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; | 139 | ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; |
150 | ht_cap->ampdu_density = | 140 | ht_cap.ampdu_density = |
151 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; | 141 | (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; |
152 | 142 | ||
153 | /* own MCS TX capabilities */ | 143 | /* own MCS TX capabilities */ |
154 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; | 144 | tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; |
155 | 145 | ||
156 | /* Copy peer MCS TX capabilities, the driver might need them. */ | 146 | /* Copy peer MCS TX capabilities, the driver might need them. */ |
157 | ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params; | 147 | ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; |
158 | 148 | ||
159 | /* can we TX with MCS rates? */ | 149 | /* can we TX with MCS rates? */ |
160 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) | 150 | if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) |
161 | return; | 151 | goto apply; |
162 | 152 | ||
163 | /* Counting from 0, therefore +1 */ | 153 | /* Counting from 0, therefore +1 */ |
164 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) | 154 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) |
@@ -176,25 +166,53 @@ void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | |||
176 | * - remainder are multiple spatial streams using unequal modulation | 166 | * - remainder are multiple spatial streams using unequal modulation |
177 | */ | 167 | */ |
178 | for (i = 0; i < max_tx_streams; i++) | 168 | for (i = 0; i < max_tx_streams; i++) |
179 | ht_cap->mcs.rx_mask[i] = | 169 | ht_cap.mcs.rx_mask[i] = |
180 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; | 170 | sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; |
181 | 171 | ||
182 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) | 172 | if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) |
183 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; | 173 | for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; |
184 | i < IEEE80211_HT_MCS_MASK_LEN; i++) | 174 | i < IEEE80211_HT_MCS_MASK_LEN; i++) |
185 | ht_cap->mcs.rx_mask[i] = | 175 | ht_cap.mcs.rx_mask[i] = |
186 | sband->ht_cap.mcs.rx_mask[i] & | 176 | sband->ht_cap.mcs.rx_mask[i] & |
187 | ht_cap_ie->mcs.rx_mask[i]; | 177 | ht_cap_ie->mcs.rx_mask[i]; |
188 | 178 | ||
189 | /* handle MCS rate 32 too */ | 179 | /* handle MCS rate 32 too */ |
190 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) | 180 | if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) |
191 | ht_cap->mcs.rx_mask[32/8] |= 1; | 181 | ht_cap.mcs.rx_mask[32/8] |= 1; |
192 | 182 | ||
183 | apply: | ||
193 | /* | 184 | /* |
194 | * If user has specified capability over-rides, take care | 185 | * If user has specified capability over-rides, take care |
195 | * of that here. | 186 | * of that here. |
196 | */ | 187 | */ |
197 | ieee80211_apply_htcap_overrides(sdata, ht_cap); | 188 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); |
189 | |||
190 | changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
191 | |||
192 | memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); | ||
193 | |||
194 | switch (sdata->vif.bss_conf.chandef.width) { | ||
195 | default: | ||
196 | WARN_ON_ONCE(1); | ||
197 | /* fall through */ | ||
198 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
199 | case NL80211_CHAN_WIDTH_20: | ||
200 | bw = IEEE80211_STA_RX_BW_20; | ||
201 | break; | ||
202 | case NL80211_CHAN_WIDTH_40: | ||
203 | case NL80211_CHAN_WIDTH_80: | ||
204 | case NL80211_CHAN_WIDTH_80P80: | ||
205 | case NL80211_CHAN_WIDTH_160: | ||
206 | bw = ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
207 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | if (bw != sta->sta.bandwidth) | ||
212 | changed = true; | ||
213 | sta->sta.bandwidth = bw; | ||
214 | |||
215 | return changed; | ||
198 | } | 216 | } |
199 | 217 | ||
200 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, | 218 | void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 2db1f2b90bfe..40b71dfcc79d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -496,33 +496,26 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
496 | if (sta && elems->ht_operation && elems->ht_cap_elem && | 496 | if (sta && elems->ht_operation && elems->ht_cap_elem && |
497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { | 497 | sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) { |
498 | /* we both use HT */ | 498 | /* we both use HT */ |
499 | struct ieee80211_sta_ht_cap sta_ht_cap_new; | 499 | struct ieee80211_ht_cap htcap_ie; |
500 | struct cfg80211_chan_def chandef; | 500 | struct cfg80211_chan_def chandef; |
501 | 501 | ||
502 | ieee80211_ht_oper_to_chandef(channel, | 502 | ieee80211_ht_oper_to_chandef(channel, |
503 | elems->ht_operation, | 503 | elems->ht_operation, |
504 | &chandef); | 504 | &chandef); |
505 | 505 | ||
506 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 506 | memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie)); |
507 | elems->ht_cap_elem, | ||
508 | &sta_ht_cap_new); | ||
509 | 507 | ||
510 | /* | 508 | /* |
511 | * fall back to HT20 if we don't use or use | 509 | * fall back to HT20 if we don't use or use |
512 | * the other extension channel | 510 | * the other extension channel |
513 | */ | 511 | */ |
514 | if (chandef.width != NL80211_CHAN_WIDTH_40 || | 512 | if (cfg80211_get_chandef_type(&chandef) != |
515 | cfg80211_get_chandef_type(&chandef) != | ||
516 | sdata->u.ibss.channel_type) | 513 | sdata->u.ibss.channel_type) |
517 | sta_ht_cap_new.cap &= | 514 | htcap_ie.cap_info &= |
518 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 515 | cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40); |
519 | 516 | ||
520 | if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new, | 517 | rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap( |
521 | sizeof(sta_ht_cap_new))) { | 518 | sdata, sband, &htcap_ie, sta); |
522 | memcpy(&sta->sta.ht_cap, &sta_ht_cap_new, | ||
523 | sizeof(sta_ht_cap_new)); | ||
524 | rates_updated = true; | ||
525 | } | ||
526 | } | 519 | } |
527 | 520 | ||
528 | if (sta && rates_updated) { | 521 | if (sta && rates_updated) { |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9206d43ca572..6b41d7787a5a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1384,10 +1384,10 @@ void ieee80211_purge_tx_queue(struct ieee80211_hw *hw, | |||
1384 | /* HT */ | 1384 | /* HT */ |
1385 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, | 1385 | void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, |
1386 | struct ieee80211_sta_ht_cap *ht_cap); | 1386 | struct ieee80211_sta_ht_cap *ht_cap); |
1387 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, | 1387 | bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata, |
1388 | struct ieee80211_supported_band *sband, | 1388 | struct ieee80211_supported_band *sband, |
1389 | struct ieee80211_ht_cap *ht_cap_ie, | 1389 | struct ieee80211_ht_cap *ht_cap_ie, |
1390 | struct ieee80211_sta_ht_cap *ht_cap); | 1390 | struct sta_info *sta); |
1391 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | 1391 | void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, |
1392 | const u8 *da, u16 tid, | 1392 | const u8 *da, u16 tid, |
1393 | u16 initiator, u16 reason_code); | 1393 | u16 initiator, u16 reason_code); |
@@ -1431,6 +1431,7 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
1431 | struct ieee80211_supported_band *sband, | 1431 | struct ieee80211_supported_band *sband, |
1432 | struct ieee80211_vht_cap *vht_cap_ie, | 1432 | struct ieee80211_vht_cap *vht_cap_ie, |
1433 | struct sta_info *sta); | 1433 | struct sta_info *sta); |
1434 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); | ||
1434 | 1435 | ||
1435 | /* Spectrum management */ | 1436 | /* Spectrum management */ |
1436 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1437 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a4c7a7e98d14..7765139b24aa 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -373,8 +373,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
373 | if (elems->ht_cap_elem && | 373 | if (elems->ht_cap_elem && |
374 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) | 374 | sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) |
375 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 375 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
376 | elems->ht_cap_elem, | 376 | elems->ht_cap_elem, sta); |
377 | &sta->sta.ht_cap); | ||
378 | else | 377 | else |
379 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 378 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
380 | 379 | ||
@@ -383,8 +382,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, | |||
383 | 382 | ||
384 | if (!(elems->ht_operation->ht_param & | 383 | if (!(elems->ht_operation->ht_param & |
385 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 384 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
386 | sta->sta.ht_cap.cap &= | 385 | sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; |
387 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
388 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, | 386 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
389 | elems->ht_operation, &chandef); | 387 | elems->ht_operation, &chandef); |
390 | if (sta->ch_width != chandef.width) | 388 | if (sta->ch_width != chandef.width) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 58b6e67ffbed..be1147286801 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -219,19 +219,20 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata, | |||
219 | mutex_lock(&local->sta_mtx); | 219 | mutex_lock(&local->sta_mtx); |
220 | sta = sta_info_get(sdata, bssid); | 220 | sta = sta_info_get(sdata, bssid); |
221 | 221 | ||
222 | WARN_ON_ONCE(!sta); | 222 | if (WARN_ON_ONCE(!sta)) { |
223 | mutex_unlock(&local->sta_mtx); | ||
224 | return changed; | ||
225 | } | ||
223 | 226 | ||
224 | if (sta && !sta->supports_40mhz) | 227 | if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) |
225 | disable_40 = true; | 228 | disable_40 = true; |
226 | 229 | ||
227 | if (sta && (!reconfig || | 230 | if (!reconfig || |
228 | (disable_40 != !(sta->sta.ht_cap.cap & | 231 | disable_40 != (sta->sta.bandwidth < IEEE80211_STA_RX_BW_40)) { |
229 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)))) { | ||
230 | |||
231 | if (disable_40) | 232 | if (disable_40) |
232 | sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 233 | sta->sta.bandwidth = IEEE80211_STA_RX_BW_20; |
233 | else | 234 | else |
234 | sta->sta.ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 235 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); |
235 | 236 | ||
236 | rate_control_rate_update(local, sband, sta, | 237 | rate_control_rate_update(local, sband, sta, |
237 | IEEE80211_RC_BW_CHANGED); | 238 | IEEE80211_RC_BW_CHANGED); |
@@ -2210,10 +2211,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2210 | 2211 | ||
2211 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) | 2212 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) |
2212 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, | 2213 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
2213 | elems.ht_cap_elem, &sta->sta.ht_cap); | 2214 | elems.ht_cap_elem, sta); |
2214 | |||
2215 | sta->supports_40mhz = | ||
2216 | sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2217 | 2215 | ||
2218 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) | 2216 | if (elems.vht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) |
2219 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, | 2217 | ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 6e35dcd2aa2f..6176c71d47ff 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -848,8 +848,6 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
848 | IEEE80211_HT_CAP_SM_PS_SHIFT; | 848 | IEEE80211_HT_CAP_SM_PS_SHIFT; |
849 | 849 | ||
850 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 850 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
851 | u16 req = 0; | ||
852 | |||
853 | mi->groups[i].supported = 0; | 851 | mi->groups[i].supported = 0; |
854 | if (i == MINSTREL_CCK_GROUP) { | 852 | if (i == MINSTREL_CCK_GROUP) { |
855 | minstrel_ht_update_cck(mp, mi, sband, sta); | 853 | minstrel_ht_update_cck(mp, mi, sband, sta); |
@@ -857,16 +855,17 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
857 | } | 855 | } |
858 | 856 | ||
859 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 857 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { |
860 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 858 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
861 | req |= IEEE80211_HT_CAP_SGI_40; | 859 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) |
862 | else | 860 | continue; |
863 | req |= IEEE80211_HT_CAP_SGI_20; | 861 | } else { |
862 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_20)) | ||
863 | continue; | ||
864 | } | ||
864 | } | 865 | } |
865 | 866 | ||
866 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 867 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
867 | req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 868 | sta->bandwidth < IEEE80211_STA_RX_BW_40) |
868 | |||
869 | if ((sta_cap & req) != req) | ||
870 | continue; | 869 | continue; |
871 | 870 | ||
872 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 871 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b5f1bba7ffe1..8a861a50b12f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2410,26 +2410,21 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2410 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { | 2410 | case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: { |
2411 | struct ieee80211_supported_band *sband; | 2411 | struct ieee80211_supported_band *sband; |
2412 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; | 2412 | u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth; |
2413 | bool old_40mhz, new_40mhz; | 2413 | enum ieee80211_sta_rx_bandwidth new_bw; |
2414 | 2414 | ||
2415 | /* If it doesn't support 40 MHz it can't change ... */ | 2415 | /* If it doesn't support 40 MHz it can't change ... */ |
2416 | if (!rx->sta->supports_40mhz) | 2416 | if (!(rx->sta->sta.ht_cap.cap & |
2417 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
2417 | goto handled; | 2418 | goto handled; |
2418 | 2419 | ||
2419 | old_40mhz = rx->sta->sta.ht_cap.cap & | 2420 | if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ) |
2420 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 2421 | new_bw = IEEE80211_STA_RX_BW_20; |
2421 | new_40mhz = chanwidth == IEEE80211_HT_CHANWIDTH_ANY; | 2422 | else |
2423 | new_bw = ieee80211_sta_cur_vht_bw(rx->sta); | ||
2422 | 2424 | ||
2423 | if (old_40mhz == new_40mhz) | 2425 | if (rx->sta->sta.bandwidth == new_bw) |
2424 | goto handled; | 2426 | goto handled; |
2425 | 2427 | ||
2426 | if (new_40mhz) | ||
2427 | rx->sta->sta.ht_cap.cap |= | ||
2428 | IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2429 | else | ||
2430 | rx->sta->sta.ht_cap.cap &= | ||
2431 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
2432 | |||
2433 | sband = rx->local->hw.wiphy->bands[status->band]; | 2428 | sband = rx->local->hw.wiphy->bands[status->band]; |
2434 | 2429 | ||
2435 | rate_control_rate_update(local, sband, rx->sta, | 2430 | rate_control_rate_update(local, sband, rx->sta, |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 350578c396c0..03c42f8d39f0 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -296,8 +296,6 @@ struct sta_ampdu_mlme { | |||
296 | * @sta: station information we share with the driver | 296 | * @sta: station information we share with the driver |
297 | * @sta_state: duplicates information about station state (for debug) | 297 | * @sta_state: duplicates information about station state (for debug) |
298 | * @beacon_loss_count: number of times beacon loss has triggered | 298 | * @beacon_loss_count: number of times beacon loss has triggered |
299 | * @supports_40mhz: tracks whether the station advertised 40 MHz support | ||
300 | * as we overwrite its HT parameters with the currently used value | ||
301 | * @rcu_head: RCU head used for freeing this station struct | 299 | * @rcu_head: RCU head used for freeing this station struct |
302 | */ | 300 | */ |
303 | struct sta_info { | 301 | struct sta_info { |
@@ -403,8 +401,6 @@ struct sta_info { | |||
403 | unsigned int lost_packets; | 401 | unsigned int lost_packets; |
404 | unsigned int beacon_loss_count; | 402 | unsigned int beacon_loss_count; |
405 | 403 | ||
406 | bool supports_40mhz; | ||
407 | |||
408 | /* keep last! */ | 404 | /* keep last! */ |
409 | struct ieee80211_sta sta; | 405 | struct ieee80211_sta sta; |
410 | }; | 406 | }; |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 1606aa165d5f..0fc9a2fb8d53 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c | |||
@@ -27,6 +27,10 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
27 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) | 27 | if (!vht_cap_ie || !sband->vht_cap.vht_supported) |
28 | return; | 28 | return; |
29 | 29 | ||
30 | /* A VHT STA must support 40 MHz */ | ||
31 | if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
32 | return; | ||
33 | |||
30 | vht_cap->vht_supported = true; | 34 | vht_cap->vht_supported = true; |
31 | 35 | ||
32 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); | 36 | vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); |
@@ -34,4 +38,39 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, | |||
34 | /* Copy peer MCS info, the driver might need them. */ | 38 | /* Copy peer MCS info, the driver might need them. */ |
35 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, | 39 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
36 | sizeof(struct ieee80211_vht_mcs_info)); | 40 | sizeof(struct ieee80211_vht_mcs_info)); |
41 | |||
42 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); | ||
43 | } | ||
44 | |||
45 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) | ||
46 | { | ||
47 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
48 | u32 cap = sta->sta.vht_cap.cap; | ||
49 | |||
50 | if (!sta->sta.vht_cap.vht_supported) | ||
51 | return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
52 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
53 | |||
54 | /* TODO: handle VHT opmode notification data */ | ||
55 | |||
56 | switch (sdata->vif.bss_conf.chandef.width) { | ||
57 | default: | ||
58 | WARN_ON_ONCE(1); | ||
59 | /* fall through */ | ||
60 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
61 | case NL80211_CHAN_WIDTH_20: | ||
62 | case NL80211_CHAN_WIDTH_40: | ||
63 | return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? | ||
64 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; | ||
65 | case NL80211_CHAN_WIDTH_160: | ||
66 | if (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) | ||
67 | return IEEE80211_STA_RX_BW_160; | ||
68 | /* fall through */ | ||
69 | case NL80211_CHAN_WIDTH_80P80: | ||
70 | if (cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) | ||
71 | return IEEE80211_STA_RX_BW_160; | ||
72 | /* fall through */ | ||
73 | case NL80211_CHAN_WIDTH_80: | ||
74 | return IEEE80211_STA_RX_BW_80; | ||
75 | } | ||
37 | } | 76 | } |