diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 6c2adc58d654a16c00f2b68146532235d0843a47..dfdbea6e8f99530f05ce3c7fec062f2a6ff1a381 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -471,6 +471,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, struct iwl_rxon_context *tmp; struct ieee80211_sta *sta; struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct ieee80211_sta_ht_cap *ht_cap; bool need_multiple; lockdep_assert_held(&priv->mutex); @@ -479,23 +480,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, case NL80211_IFTYPE_STATION: rcu_read_lock(); sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int maxstreams; - - maxstreams = (ht_cap->mcs.tx_params & - IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) - >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - maxstreams += 1; - - need_multiple = true; - - if ((ht_cap->mcs.rx_mask[1] == 0) && - (ht_cap->mcs.rx_mask[2] == 0)) - need_multiple = false; - if (maxstreams <= 1) - need_multiple = false; - } else { + if (!sta) { /* * If at all, this can only happen through a race * when the AP disconnects us while we're still @@ -503,7 +488,46 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, * will soon tell us about that. */ need_multiple = false; + rcu_read_unlock(); + break; + } + + ht_cap = &sta->ht_cap; + + need_multiple = true; + + /* + * If the peer advertises no support for receiving 2 and 3 + * stream MCS rates, it can't be transmitting them either. + */ + if (ht_cap->mcs.rx_mask[1] == 0 && + ht_cap->mcs.rx_mask[2] == 0) { + need_multiple = false; + } else if (!(ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_DEFINED)) { + /* If it can't TX MCS at all ... */ + need_multiple = false; + } else if (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_RX_DIFF) { + int maxstreams; + + /* + * But if it can receive them, it might still not + * be able to transmit them, which is what we need + * to check here -- so check the number of streams + * it advertises for TX (if different from RX). + */ + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK); + maxstreams >>= + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if (maxstreams <= 1) + need_multiple = false; } + rcu_read_unlock(); break; case NL80211_IFTYPE_ADHOC: