aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c27
2 files changed, 33 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index a8223c4cc97c..c4bfba6f3c2b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -471,10 +471,11 @@ static void rs_tx_status(void *priv_rate,
471 return; 471 return;
472 } 472 }
473 473
474 rcu_read_lock();
475
474 sta = sta_info_get(local, hdr->addr1); 476 sta = sta_info_get(local, hdr->addr1);
475 if (!sta || !sta->rate_ctrl_priv) { 477 if (!sta || !sta->rate_ctrl_priv) {
476 if (sta) 478 rcu_read_unlock();
477 sta_info_put(sta);
478 IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); 479 IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
479 return; 480 return;
480 } 481 }
@@ -547,7 +548,7 @@ static void rs_tx_status(void *priv_rate,
547 548
548 spin_unlock_irqrestore(&rs_sta->lock, flags); 549 spin_unlock_irqrestore(&rs_sta->lock, flags);
549 550
550 sta_info_put(sta); 551 rcu_read_unlock();
551 552
552 IWL_DEBUG_RATE("leave\n"); 553 IWL_DEBUG_RATE("leave\n");
553 554
@@ -658,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
658 659
659 IWL_DEBUG_RATE("enter\n"); 660 IWL_DEBUG_RATE("enter\n");
660 661
662 rcu_read_lock();
663
661 sta = sta_info_get(local, hdr->addr1); 664 sta = sta_info_get(local, hdr->addr1);
662 665
663 /* Send management frames and broadcast/multicast data using lowest 666 /* Send management frames and broadcast/multicast data using lowest
@@ -668,8 +671,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
668 !sta || !sta->rate_ctrl_priv) { 671 !sta || !sta->rate_ctrl_priv) {
669 IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); 672 IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
670 sel->rate = rate_lowest(local, band, sta); 673 sel->rate = rate_lowest(local, band, sta);
671 if (sta) 674 rcu_read_unlock();
672 sta_info_put(sta);
673 return; 675 return;
674 } 676 }
675 677
@@ -811,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
811 else 813 else
812 sta->txrate_idx = sta->last_txrate_idx; 814 sta->txrate_idx = sta->last_txrate_idx;
813 815
814 sta_info_put(sta); 816 rcu_read_unlock();
815 817
816 IWL_DEBUG_RATE("leave: %d\n", index); 818 IWL_DEBUG_RATE("leave: %d\n", index);
817 819
@@ -843,13 +845,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
843 unsigned long now = jiffies; 845 unsigned long now = jiffies;
844 u32 max_time = 0; 846 u32 max_time = 0;
845 847
848 rcu_read_lock();
849
846 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); 850 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
847 if (!sta || !sta->rate_ctrl_priv) { 851 if (!sta || !sta->rate_ctrl_priv) {
848 if (sta) { 852 if (sta)
849 sta_info_put(sta);
850 IWL_DEBUG_RATE("leave - no private rate data!\n"); 853 IWL_DEBUG_RATE("leave - no private rate data!\n");
851 } else 854 else
852 IWL_DEBUG_RATE("leave - no station!\n"); 855 IWL_DEBUG_RATE("leave - no station!\n");
856 rcu_read_unlock();
853 return sprintf(buf, "station %d not found\n", sta_id); 857 return sprintf(buf, "station %d not found\n", sta_id);
854 } 858 }
855 859
@@ -890,7 +894,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
890 i = j; 894 i = j;
891 } 895 }
892 spin_unlock_irqrestore(&rs_sta->lock, flags); 896 spin_unlock_irqrestore(&rs_sta->lock, flags);
893 sta_info_put(sta); 897 rcu_read_unlock();
894 898
895 /* Display the average rate of all samples taken. 899 /* Display the average rate of all samples taken.
896 * 900 *
@@ -927,11 +931,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
927 return; 931 return;
928 } 932 }
929 933
934 rcu_read_lock();
935
930 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); 936 sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
931 if (!sta || !sta->rate_ctrl_priv) { 937 if (!sta || !sta->rate_ctrl_priv) {
932 if (sta)
933 sta_info_put(sta);
934 IWL_DEBUG_RATE("leave - no private rate data!\n"); 938 IWL_DEBUG_RATE("leave - no private rate data!\n");
939 rcu_read_unlock();
935 return; 940 return;
936 } 941 }
937 942
@@ -958,7 +963,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
958 break; 963 break;
959 } 964 }
960 965
961 sta_info_put(sta); 966 rcu_read_unlock();
962 spin_unlock_irqrestore(&rs_sta->lock, flags); 967 spin_unlock_irqrestore(&rs_sta->lock, flags);
963 968
964 rssi = priv->last_rx_rssi; 969 rssi = priv->last_rx_rssi;
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