diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 95 | ||||
-rw-r--r-- | net/mac80211/rate.c | 15 |
3 files changed, 99 insertions, 12 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 611abfcfb5eb..076409526bcb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -335,6 +335,7 @@ enum ieee80211_sta_flags { | |||
335 | IEEE80211_STA_DISABLE_VHT = BIT(11), | 335 | IEEE80211_STA_DISABLE_VHT = BIT(11), |
336 | IEEE80211_STA_DISABLE_80P80MHZ = BIT(12), | 336 | IEEE80211_STA_DISABLE_80P80MHZ = BIT(12), |
337 | IEEE80211_STA_DISABLE_160MHZ = BIT(13), | 337 | IEEE80211_STA_DISABLE_160MHZ = BIT(13), |
338 | IEEE80211_STA_DISABLE_WMM = BIT(14), | ||
338 | }; | 339 | }; |
339 | 340 | ||
340 | struct ieee80211_mgd_auth_data { | 341 | struct ieee80211_mgd_auth_data { |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86e4ad56b573..54ebc8155b49 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -2717,7 +2717,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2717 | */ | 2717 | */ |
2718 | ifmgd->wmm_last_param_set = -1; | 2718 | ifmgd->wmm_last_param_set = -1; |
2719 | 2719 | ||
2720 | if (elems.wmm_param) | 2720 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && elems.wmm_param) |
2721 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | 2721 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, |
2722 | elems.wmm_param_len); | 2722 | elems.wmm_param_len); |
2723 | else | 2723 | else |
@@ -3152,7 +3152,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3152 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 3152 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
3153 | &elems, true); | 3153 | &elems, true); |
3154 | 3154 | ||
3155 | if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | 3155 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && |
3156 | ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, | ||
3156 | elems.wmm_param_len)) | 3157 | elems.wmm_param_len)) |
3157 | changed |= BSS_CHANGED_QOS; | 3158 | changed |= BSS_CHANGED_QOS; |
3158 | 3159 | ||
@@ -4135,6 +4136,44 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
4135 | return err; | 4136 | return err; |
4136 | } | 4137 | } |
4137 | 4138 | ||
4139 | static bool ieee80211_usable_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
4140 | const u8 *wmm_param, int len) | ||
4141 | { | ||
4142 | const u8 *pos; | ||
4143 | size_t left; | ||
4144 | |||
4145 | if (len < 8) | ||
4146 | return false; | ||
4147 | |||
4148 | if (wmm_param[5] != 1 /* version */) | ||
4149 | return false; | ||
4150 | |||
4151 | pos = wmm_param + 8; | ||
4152 | left = len - 8; | ||
4153 | |||
4154 | for (; left >= 4; left -= 4, pos += 4) { | ||
4155 | u8 aifsn = pos[0] & 0x0f; | ||
4156 | u8 ecwmin = pos[1] & 0x0f; | ||
4157 | u8 ecwmax = (pos[1] & 0xf0) >> 4; | ||
4158 | int aci = (pos[0] >> 5) & 0x03; | ||
4159 | |||
4160 | if (aifsn < 2) { | ||
4161 | sdata_info(sdata, | ||
4162 | "AP has invalid WMM params (AIFSN=%d for ACI %d), disabling WMM\n", | ||
4163 | aifsn, aci); | ||
4164 | return false; | ||
4165 | } | ||
4166 | if (ecwmin > ecwmax) { | ||
4167 | sdata_info(sdata, | ||
4168 | "AP has invalid WMM params (ECWmin/max=%d/%d for ACI %d), disabling WMM\n", | ||
4169 | ecwmin, ecwmax, aci); | ||
4170 | return false; | ||
4171 | } | ||
4172 | } | ||
4173 | |||
4174 | return true; | ||
4175 | } | ||
4176 | |||
4138 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 4177 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
4139 | struct cfg80211_assoc_request *req) | 4178 | struct cfg80211_assoc_request *req) |
4140 | { | 4179 | { |
@@ -4192,9 +4231,45 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4192 | } | 4231 | } |
4193 | 4232 | ||
4194 | /* prepare assoc data */ | 4233 | /* prepare assoc data */ |
4195 | 4234 | ||
4196 | ifmgd->beacon_crc_valid = false; | 4235 | ifmgd->beacon_crc_valid = false; |
4197 | 4236 | ||
4237 | assoc_data->wmm = bss->wmm_used && | ||
4238 | (local->hw.queues >= IEEE80211_NUM_ACS); | ||
4239 | if (assoc_data->wmm) { | ||
4240 | /* try to check validity of WMM params IE */ | ||
4241 | const struct cfg80211_bss_ies *ies; | ||
4242 | const u8 *wp, *start, *end; | ||
4243 | |||
4244 | rcu_read_lock(); | ||
4245 | ies = rcu_dereference(req->bss->ies); | ||
4246 | start = ies->data; | ||
4247 | end = start + ies->len; | ||
4248 | |||
4249 | while (true) { | ||
4250 | wp = cfg80211_find_vendor_ie( | ||
4251 | WLAN_OUI_MICROSOFT, | ||
4252 | WLAN_OUI_TYPE_MICROSOFT_WMM, | ||
4253 | start, end - start); | ||
4254 | if (!wp) | ||
4255 | break; | ||
4256 | start = wp + wp[1] + 2; | ||
4257 | /* if this IE is too short, try the next */ | ||
4258 | if (wp[1] <= 4) | ||
4259 | continue; | ||
4260 | /* if this IE is WMM params, we found what we wanted */ | ||
4261 | if (wp[6] == 1) | ||
4262 | break; | ||
4263 | } | ||
4264 | |||
4265 | if (!wp || !ieee80211_usable_wmm_params(sdata, wp + 2, | ||
4266 | wp[1] - 2)) { | ||
4267 | assoc_data->wmm = false; | ||
4268 | ifmgd->flags |= IEEE80211_STA_DISABLE_WMM; | ||
4269 | } | ||
4270 | rcu_read_unlock(); | ||
4271 | } | ||
4272 | |||
4198 | /* | 4273 | /* |
4199 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | 4274 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. |
4200 | * We still associate in non-HT mode (11a/b/g) if any one of these | 4275 | * We still associate in non-HT mode (11a/b/g) if any one of these |
@@ -4224,18 +4299,22 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4224 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ | 4299 | /* Also disable HT if we don't support it or the AP doesn't use WMM */ |
4225 | sband = local->hw.wiphy->bands[req->bss->channel->band]; | 4300 | sband = local->hw.wiphy->bands[req->bss->channel->band]; |
4226 | if (!sband->ht_cap.ht_supported || | 4301 | if (!sband->ht_cap.ht_supported || |
4227 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 4302 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used || |
4303 | ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { | ||
4228 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; | 4304 | ifmgd->flags |= IEEE80211_STA_DISABLE_HT; |
4229 | if (!bss->wmm_used) | 4305 | if (!bss->wmm_used && |
4306 | !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM)) | ||
4230 | netdev_info(sdata->dev, | 4307 | netdev_info(sdata->dev, |
4231 | "disabling HT as WMM/QoS is not supported by the AP\n"); | 4308 | "disabling HT as WMM/QoS is not supported by the AP\n"); |
4232 | } | 4309 | } |
4233 | 4310 | ||
4234 | /* disable VHT if we don't support it or the AP doesn't use WMM */ | 4311 | /* disable VHT if we don't support it or the AP doesn't use WMM */ |
4235 | if (!sband->vht_cap.vht_supported || | 4312 | if (!sband->vht_cap.vht_supported || |
4236 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) { | 4313 | local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used || |
4314 | ifmgd->flags & IEEE80211_STA_DISABLE_WMM) { | ||
4237 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; | 4315 | ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; |
4238 | if (!bss->wmm_used) | 4316 | if (!bss->wmm_used && |
4317 | !(ifmgd->flags & IEEE80211_STA_DISABLE_WMM)) | ||
4239 | netdev_info(sdata->dev, | 4318 | netdev_info(sdata->dev, |
4240 | "disabling VHT as WMM/QoS is not supported by the AP\n"); | 4319 | "disabling VHT as WMM/QoS is not supported by the AP\n"); |
4241 | } | 4320 | } |
@@ -4264,8 +4343,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
4264 | sdata->smps_mode = ifmgd->req_smps; | 4343 | sdata->smps_mode = ifmgd->req_smps; |
4265 | 4344 | ||
4266 | assoc_data->capability = req->bss->capability; | 4345 | assoc_data->capability = req->bss->capability; |
4267 | assoc_data->wmm = bss->wmm_used && | ||
4268 | (local->hw.queues >= IEEE80211_NUM_ACS); | ||
4269 | assoc_data->supp_rates = bss->supp_rates; | 4346 | assoc_data->supp_rates = bss->supp_rates; |
4270 | assoc_data->supp_rates_len = bss->supp_rates_len; | 4347 | assoc_data->supp_rates_len = bss->supp_rates_len; |
4271 | 4348 | ||
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index e126605cec66..22b223f13c9f 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -235,7 +235,8 @@ static void rc_send_low_basicrate(s8 *idx, u32 basic_rates, | |||
235 | static void __rate_control_send_low(struct ieee80211_hw *hw, | 235 | static void __rate_control_send_low(struct ieee80211_hw *hw, |
236 | struct ieee80211_supported_band *sband, | 236 | struct ieee80211_supported_band *sband, |
237 | struct ieee80211_sta *sta, | 237 | struct ieee80211_sta *sta, |
238 | struct ieee80211_tx_info *info) | 238 | struct ieee80211_tx_info *info, |
239 | u32 rate_mask) | ||
239 | { | 240 | { |
240 | int i; | 241 | int i; |
241 | u32 rate_flags = | 242 | u32 rate_flags = |
@@ -247,6 +248,12 @@ static void __rate_control_send_low(struct ieee80211_hw *hw, | |||
247 | 248 | ||
248 | info->control.rates[0].idx = 0; | 249 | info->control.rates[0].idx = 0; |
249 | for (i = 0; i < sband->n_bitrates; i++) { | 250 | for (i = 0; i < sband->n_bitrates; i++) { |
251 | if (!(rate_mask & BIT(i))) | ||
252 | continue; | ||
253 | |||
254 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
255 | continue; | ||
256 | |||
250 | if (!rate_supported(sta, sband->band, i)) | 257 | if (!rate_supported(sta, sband->band, i)) |
251 | continue; | 258 | continue; |
252 | 259 | ||
@@ -274,7 +281,8 @@ bool rate_control_send_low(struct ieee80211_sta *pubsta, | |||
274 | bool use_basicrate = false; | 281 | bool use_basicrate = false; |
275 | 282 | ||
276 | if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { | 283 | if (!pubsta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) { |
277 | __rate_control_send_low(txrc->hw, sband, pubsta, info); | 284 | __rate_control_send_low(txrc->hw, sband, pubsta, info, |
285 | txrc->rate_idx_mask); | ||
278 | 286 | ||
279 | if (!pubsta && txrc->bss) { | 287 | if (!pubsta && txrc->bss) { |
280 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; | 288 | mcast_rate = txrc->bss_conf->mcast_rate[sband->band]; |
@@ -656,7 +664,8 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, | |||
656 | rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates); | 664 | rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates); |
657 | 665 | ||
658 | if (dest[0].idx < 0) | 666 | if (dest[0].idx < 0) |
659 | __rate_control_send_low(&sdata->local->hw, sband, sta, info); | 667 | __rate_control_send_low(&sdata->local->hw, sband, sta, info, |
668 | sdata->rc_rateidx_mask[info->band]); | ||
660 | 669 | ||
661 | if (sta) | 670 | if (sta) |
662 | rate_fixup_ratelist(vif, sband, info, dest, max_rates); | 671 | rate_fixup_ratelist(vif, sband, info, dest, max_rates); |