iwlagn: fix iwlagn_check_needed_chains
authorJohannes Berg <johannes.berg@intel.com>
Fri, 25 Feb 2011 11:24:11 +0000 (12:24 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 25 Feb 2011 20:33:39 +0000 (15:33 -0500)
This function was intended to calculate the
number of RX chains needed, but could only
work where the AP's streams were asymmetric,
i.e. 2 TX and 3 RX or similar. In the case
where IEEE80211_HT_MCS_TX_RX_DIFF was not
set, this function would calculate the wrong
information.

Additionally, mac80211 didn't pass through
the required values at all, so it couldn't
work anyway.

Rewrite the logic in this function and add
appropriate comments to make it readable.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c

index 6c2adc58d654a16c00f2b68146532235d0843a47..dfdbea6e8f99530f05ce3c7fec062f2a6ff1a381 100644 (file)
@@ -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: