aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/mlme.c95
-rw-r--r--net/mac80211/rate.c15
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
340struct ieee80211_mgd_auth_data { 341struct 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
4139static 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
4138int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, 4177int 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,
235static void __rate_control_send_low(struct ieee80211_hw *hw, 235static 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);