aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-03-06 15:30:46 -0500
commitd0709a65181beb787ef3f58cfe45536a2bb254c8 (patch)
tree29e5f36583b0e0a3f11b291347e57672eab41dad /drivers/net/wireless/iwlwifi/iwl-4965-rs.c
parent5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (diff)
mac80211: RCU-ify STA info structure access
This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-4965-rs.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 48a6a85355ec..46d85fd07faa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -847,12 +847,12 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
847 if (retries > 15) 847 if (retries > 15)
848 retries = 15; 848 retries = 15;
849 849
850 rcu_read_lock();
850 851
851 sta = sta_info_get(local, hdr->addr1); 852 sta = sta_info_get(local, hdr->addr1);
852 853
853 if (!sta || !sta->rate_ctrl_priv) { 854 if (!sta || !sta->rate_ctrl_priv) {
854 if (sta) 855 rcu_read_unlock();
855 sta_info_put(sta);
856 return; 856 return;
857 } 857 }
858 858
@@ -891,7 +891,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
891 if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { 891 if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
892 IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", 892 IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
893 rs_index, tx_mcs.rate_n_flags); 893 rs_index, tx_mcs.rate_n_flags);
894 sta_info_put(sta); 894 rcu_read_unlock();
895 return; 895 return;
896 } 896 }
897 897
@@ -909,7 +909,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
909 IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", 909 IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
910 tx_mcs.rate_n_flags, 910 tx_mcs.rate_n_flags,
911 le32_to_cpu(table->rs_table[0].rate_n_flags)); 911 le32_to_cpu(table->rs_table[0].rate_n_flags));
912 sta_info_put(sta); 912 rcu_read_unlock();
913 return; 913 return;
914 } 914 }
915 915
@@ -1025,7 +1025,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
1025 1025
1026 /* See if there's a better rate or modulation mode to try. */ 1026 /* See if there's a better rate or modulation mode to try. */
1027 rs_rate_scale_perform(priv, dev, hdr, sta); 1027 rs_rate_scale_perform(priv, dev, hdr, sta);
1028 sta_info_put(sta); 1028 rcu_read_unlock();
1029 return; 1029 return;
1030} 1030}
1031 1031
@@ -2219,6 +2219,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
2219 2219
2220 IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); 2220 IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
2221 2221
2222 rcu_read_lock();
2223
2222 sta = sta_info_get(local, hdr->addr1); 2224 sta = sta_info_get(local, hdr->addr1);
2223 2225
2224 /* Send management frames and broadcast/multicast data using lowest 2226 /* Send management frames and broadcast/multicast data using lowest
@@ -2227,8 +2229,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
2227 if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || 2229 if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
2228 !sta || !sta->rate_ctrl_priv) { 2230 !sta || !sta->rate_ctrl_priv) {
2229 sel->rate = rate_lowest(local, sband, sta); 2231 sel->rate = rate_lowest(local, sband, sta);
2230 if (sta) 2232 rcu_read_unlock();
2231 sta_info_put(sta);
2232 return; 2233 return;
2233 } 2234 }
2234 2235
@@ -2261,7 +2262,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
2261 sel->rate = rate_lowest(local, sband, sta); 2262 sel->rate = rate_lowest(local, sband, sta);
2262 return; 2263 return;
2263 } 2264 }
2264 sta_info_put(sta); 2265 rcu_read_unlock();
2265 2266
2266 sel->rate = &priv->ieee_rates[i]; 2267 sel->rate = &priv->ieee_rates[i];
2267} 2268}
@@ -2735,13 +2736,15 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
2735 u32 max_time = 0; 2736 u32 max_time = 0;
2736 u8 lq_type, antenna; 2737 u8 lq_type, antenna;
2737 2738
2739 rcu_read_lock();
2740
2738 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); 2741 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
2739 if (!sta || !sta->rate_ctrl_priv) { 2742 if (!sta || !sta->rate_ctrl_priv) {
2740 if (sta) { 2743 if (sta)
2741 sta_info_put(sta);
2742 IWL_DEBUG_RATE("leave - no private rate data!\n"); 2744 IWL_DEBUG_RATE("leave - no private rate data!\n");
2743 } else 2745 else
2744 IWL_DEBUG_RATE("leave - no station!\n"); 2746 IWL_DEBUG_RATE("leave - no station!\n");
2747 rcu_read_unlock();
2745 return sprintf(buf, "station %d not found\n", sta_id); 2748 return sprintf(buf, "station %d not found\n", sta_id);
2746 } 2749 }
2747 2750
@@ -2808,7 +2811,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
2808 "active_search %d rate index %d\n", lq_type, antenna, 2811 "active_search %d rate index %d\n", lq_type, antenna,
2809 lq_sta->search_better_tbl, sta->last_txrate_idx); 2812 lq_sta->search_better_tbl, sta->last_txrate_idx);
2810 2813
2811 sta_info_put(sta); 2814 rcu_read_unlock();
2812 return cnt; 2815 return cnt;
2813} 2816}
2814 2817