]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
iwlwifi: fix rs_get_rate WARN_ON()
authorAbbas, Mohamed <mohamed.abbas@intel.com>
Wed, 21 Jan 2009 18:58:02 +0000 (10:58 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 6 Feb 2009 21:47:20 +0000 (13:47 -0800)
commit c338ba3ca5bef2df2082d9e8d336ff7b2880c326 upstream.

In ieee80211_sta structure there is u64 supp_rates[IEEE80211_NUM_BANDS]
this is filled with all support rate from assoc_resp.  If we associate
with G-band AP only supp_rates of G-band will be set the other band
supp_rates will be set to 0. If the user type this command
this will cause mac80211 to set to new channel, mac80211
does not disassociate in setting new channel, so the active
band is now A-band. then in handling the new essid mac80211 will
kick in the assoc steps which involve sending disassociation frame.
in this mac80211 will WARN_ON sta->supp_rates[A_BAND] == 0.

This fixes:
http://www.intellinuxwireless.org/bugzilla/show_bug.cgi?id=1822
http://www.kerneloops.org/searchweek.php?search=rs_get_rate

Signed-off-by: mohamed abbas <mohamed.abbas@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c

index 6fc5e7361f267dad0e01deb1a5c2a155cdc72bc6..6500599c76e6f1c4a8e07ec341cb48e9812af3fc 100644 (file)
@@ -647,12 +647,16 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
        s8 scale_action = 0;
        unsigned long flags;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       u16 fc, rate_mask;
+       u16 fc;
+       u16 rate_mask = 0;
        struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
        DECLARE_MAC_BUF(mac);
 
        IWL_DEBUG_RATE("enter\n");
 
+       if (sta)
+               rate_mask = sta->supp_rates[sband->band];
+
        /* Send management frames and broadcast/multicast data using lowest
         * rate. */
        fc = le16_to_cpu(hdr->frame_control);
@@ -660,11 +664,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
            is_multicast_ether_addr(hdr->addr1) ||
            !sta || !priv_sta) {
                IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               if (!rate_mask)
+                       sel->rate_idx = rate_lowest_index(sband, NULL);
+               else
+                       sel->rate_idx = rate_lowest_index(sband, sta);
                return;
        }
 
-       rate_mask = sta->supp_rates[sband->band];
        index = min(rs_sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1);
 
        if (sband->band == IEEE80211_BAND_5GHZ)
index e2a58e477036e611da5ffc78abeda5748f7392ce..af2354dcd63c24c121f18dfc4976d374094ea35a 100644 (file)
@@ -951,7 +951,8 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        }
 
        /* See if there's a better rate or modulation mode to try. */
-       rs_rate_scale_perform(priv, hdr, sta, lq_sta);
+       if (sta && sta->supp_rates[sband->band])
+               rs_rate_scale_perform(priv, hdr, sta, lq_sta);
 out:
        return;
 }
@@ -2114,15 +2115,22 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        __le16 fc;
        struct iwl_lq_sta *lq_sta;
+       u64 mask_bit = 0;
 
        IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
+       if (sta)
+               mask_bit = sta->supp_rates[sband->band];
+
        /* Send management frames and broadcast/multicast data using lowest
         * rate. */
        fc = hdr->frame_control;
        if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
            !sta || !priv_sta) {
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               if (!mask_bit)
+                       sel->rate_idx = rate_lowest_index(sband, NULL);
+               else
+                       sel->rate_idx = rate_lowest_index(sband, sta);
                return;
        }