diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 10:27:46 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:46 -0500 |
commit | d0709a65181beb787ef3f58cfe45536a2bb254c8 (patch) | |
tree | 29e5f36583b0e0a3f11b291347e57672eab41dad /net/mac80211/rx.c | |
parent | 5cf121c3cdb955583bf0c5d28c992b7968a4aa1a (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 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 24 |
1 files changed, 8 insertions, 16 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2e65ca1cd1aa..8e1e2859bfd5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -631,7 +631,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) | |||
631 | struct ieee80211_sub_if_data *sdata; | 631 | struct ieee80211_sub_if_data *sdata; |
632 | DECLARE_MAC_BUF(mac); | 632 | DECLARE_MAC_BUF(mac); |
633 | 633 | ||
634 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 634 | sdata = sta->sdata; |
635 | 635 | ||
636 | if (sdata->bss) | 636 | if (sdata->bss) |
637 | atomic_inc(&sdata->bss->num_sta_ps); | 637 | atomic_inc(&sdata->bss->num_sta_ps); |
@@ -652,7 +652,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) | |||
652 | struct ieee80211_tx_packet_data *pkt_data; | 652 | struct ieee80211_tx_packet_data *pkt_data; |
653 | DECLARE_MAC_BUF(mac); | 653 | DECLARE_MAC_BUF(mac); |
654 | 654 | ||
655 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 655 | sdata = sta->sdata; |
656 | 656 | ||
657 | if (sdata->bss) | 657 | if (sdata->bss) |
658 | atomic_dec(&sdata->bss->num_sta_ps); | 658 | atomic_dec(&sdata->bss->num_sta_ps); |
@@ -1287,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1287 | "multicast frame\n", dev->name); | 1287 | "multicast frame\n", dev->name); |
1288 | } else { | 1288 | } else { |
1289 | dsta = sta_info_get(local, skb->data); | 1289 | dsta = sta_info_get(local, skb->data); |
1290 | if (dsta && dsta->dev == dev) { | 1290 | if (dsta && dsta->sdata->dev == dev) { |
1291 | /* | 1291 | /* |
1292 | * The destination station is associated to | 1292 | * The destination station is associated to |
1293 | * this AP (in this VLAN), so send the frame | 1293 | * this AP (in this VLAN), so send the frame |
@@ -1297,8 +1297,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1297 | xmit_skb = skb; | 1297 | xmit_skb = skb; |
1298 | skb = NULL; | 1298 | skb = NULL; |
1299 | } | 1299 | } |
1300 | if (dsta) | ||
1301 | sta_info_put(dsta); | ||
1302 | } | 1300 | } |
1303 | } | 1301 | } |
1304 | 1302 | ||
@@ -1905,13 +1903,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1905 | 1903 | ||
1906 | rx.sta = sta_info_get(local, hdr->addr2); | 1904 | rx.sta = sta_info_get(local, hdr->addr2); |
1907 | if (rx.sta) { | 1905 | if (rx.sta) { |
1908 | rx.dev = rx.sta->dev; | 1906 | rx.sdata = rx.sta->sdata; |
1909 | rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); | 1907 | rx.dev = rx.sta->sdata->dev; |
1910 | } | 1908 | } |
1911 | 1909 | ||
1912 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { | 1910 | if ((status->flag & RX_FLAG_MMIC_ERROR)) { |
1913 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); | 1911 | ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); |
1914 | goto end; | 1912 | return; |
1915 | } | 1913 | } |
1916 | 1914 | ||
1917 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) | 1915 | if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) |
@@ -1970,10 +1968,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
1970 | ieee80211_invoke_rx_handlers(prev, &rx, skb); | 1968 | ieee80211_invoke_rx_handlers(prev, &rx, skb); |
1971 | } else | 1969 | } else |
1972 | dev_kfree_skb(skb); | 1970 | dev_kfree_skb(skb); |
1973 | |||
1974 | end: | ||
1975 | if (rx.sta) | ||
1976 | sta_info_put(rx.sta); | ||
1977 | } | 1971 | } |
1978 | 1972 | ||
1979 | #define SEQ_MODULO 0x1000 | 1973 | #define SEQ_MODULO 0x1000 |
@@ -2150,7 +2144,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2150 | /* if this mpdu is fragmented - terminate rx aggregation session */ | 2144 | /* if this mpdu is fragmented - terminate rx aggregation session */ |
2151 | sc = le16_to_cpu(hdr->seq_ctrl); | 2145 | sc = le16_to_cpu(hdr->seq_ctrl); |
2152 | if (sc & IEEE80211_SCTL_FRAG) { | 2146 | if (sc & IEEE80211_SCTL_FRAG) { |
2153 | ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, | 2147 | ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, |
2154 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); | 2148 | tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); |
2155 | ret = 1; | 2149 | ret = 1; |
2156 | goto end_reorder; | 2150 | goto end_reorder; |
@@ -2160,9 +2154,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, | |||
2160 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; | 2154 | mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; |
2161 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, | 2155 | ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, |
2162 | mpdu_seq_num, 0); | 2156 | mpdu_seq_num, 0); |
2163 | end_reorder: | 2157 | end_reorder: |
2164 | if (sta) | ||
2165 | sta_info_put(sta); | ||
2166 | return ret; | 2158 | return ret; |
2167 | } | 2159 | } |
2168 | 2160 | ||