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/tx.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/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 33e314f3aab7..80f4343a3007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -327,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
327 | } | 327 | } |
328 | total += skb_queue_len(&ap->ps_bc_buf); | 328 | total += skb_queue_len(&ap->ps_bc_buf); |
329 | } | 329 | } |
330 | rcu_read_unlock(); | ||
331 | 330 | ||
332 | read_lock_bh(&local->sta_lock); | 331 | list_for_each_entry_rcu(sta, &local->sta_list, list) { |
333 | list_for_each_entry(sta, &local->sta_list, list) { | ||
334 | skb = skb_dequeue(&sta->ps_tx_buf); | 332 | skb = skb_dequeue(&sta->ps_tx_buf); |
335 | if (skb) { | 333 | if (skb) { |
336 | purged++; | 334 | purged++; |
@@ -338,7 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
338 | } | 336 | } |
339 | total += skb_queue_len(&sta->ps_tx_buf); | 337 | total += skb_queue_len(&sta->ps_tx_buf); |
340 | } | 338 | } |
341 | read_unlock_bh(&local->sta_lock); | 339 | |
340 | rcu_read_unlock(); | ||
342 | 341 | ||
343 | local->total_ps_buffered = total; | 342 | local->total_ps_buffered = total; |
344 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 343 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", |
@@ -1141,20 +1140,17 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1141 | return 0; | 1140 | return 0; |
1142 | } | 1141 | } |
1143 | 1142 | ||
1143 | rcu_read_lock(); | ||
1144 | |||
1144 | /* initialises tx */ | 1145 | /* initialises tx */ |
1145 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); | 1146 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); |
1146 | 1147 | ||
1147 | if (res_prepare == TX_DROP) { | 1148 | if (res_prepare == TX_DROP) { |
1148 | dev_kfree_skb(skb); | 1149 | dev_kfree_skb(skb); |
1150 | rcu_read_unlock(); | ||
1149 | return 0; | 1151 | return 0; |
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | /* | ||
1153 | * key references are protected using RCU and this requires that | ||
1154 | * we are in a read-site RCU section during receive processing | ||
1155 | */ | ||
1156 | rcu_read_lock(); | ||
1157 | |||
1158 | sta = tx.sta; | 1154 | sta = tx.sta; |
1159 | tx.channel = local->hw.conf.channel; | 1155 | tx.channel = local->hw.conf.channel; |
1160 | 1156 | ||
@@ -1167,9 +1163,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, | |||
1167 | 1163 | ||
1168 | skb = tx.skb; /* handlers are allowed to change skb */ | 1164 | skb = tx.skb; /* handlers are allowed to change skb */ |
1169 | 1165 | ||
1170 | if (sta) | ||
1171 | sta_info_put(sta); | ||
1172 | |||
1173 | if (unlikely(res == TX_DROP)) { | 1166 | if (unlikely(res == TX_DROP)) { |
1174 | I802_DEBUG_INC(local->tx_handlers_drop); | 1167 | I802_DEBUG_INC(local->tx_handlers_drop); |
1175 | goto drop; | 1168 | goto drop; |
@@ -1489,11 +1482,11 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1489 | * in AP mode) | 1482 | * in AP mode) |
1490 | */ | 1483 | */ |
1491 | if (!is_multicast_ether_addr(hdr.addr1)) { | 1484 | if (!is_multicast_ether_addr(hdr.addr1)) { |
1485 | rcu_read_lock(); | ||
1492 | sta = sta_info_get(local, hdr.addr1); | 1486 | sta = sta_info_get(local, hdr.addr1); |
1493 | if (sta) { | 1487 | if (sta) |
1494 | sta_flags = sta->flags; | 1488 | sta_flags = sta->flags; |
1495 | sta_info_put(sta); | 1489 | rcu_read_unlock(); |
1496 | } | ||
1497 | } | 1490 | } |
1498 | 1491 | ||
1499 | /* receiver is QoS enabled, use a QoS type frame */ | 1492 | /* receiver is QoS enabled, use a QoS type frame */ |
@@ -1722,7 +1715,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1722 | 1715 | ||
1723 | /* Generate bitmap for TIM only if there are any STAs in power save | 1716 | /* Generate bitmap for TIM only if there are any STAs in power save |
1724 | * mode. */ | 1717 | * mode. */ |
1725 | read_lock_bh(&local->sta_lock); | ||
1726 | if (atomic_read(&bss->num_sta_ps) > 0) | 1718 | if (atomic_read(&bss->num_sta_ps) > 0) |
1727 | /* in the hope that this is faster than | 1719 | /* in the hope that this is faster than |
1728 | * checking byte-for-byte */ | 1720 | * checking byte-for-byte */ |
@@ -1773,7 +1765,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1773 | *pos++ = aid0; /* Bitmap control */ | 1765 | *pos++ = aid0; /* Bitmap control */ |
1774 | *pos++ = 0; /* Part Virt Bitmap */ | 1766 | *pos++ = 0; /* Part Virt Bitmap */ |
1775 | } | 1767 | } |
1776 | read_unlock_bh(&local->sta_lock); | ||
1777 | } | 1768 | } |
1778 | 1769 | ||
1779 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1770 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
@@ -1821,7 +1812,22 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1821 | ieee80211_include_sequence(sdata, | 1812 | ieee80211_include_sequence(sdata, |
1822 | (struct ieee80211_hdr *)skb->data); | 1813 | (struct ieee80211_hdr *)skb->data); |
1823 | 1814 | ||
1824 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | 1815 | /* |
1816 | * Not very nice, but we want to allow the driver to call | ||
1817 | * ieee80211_beacon_get() as a response to the set_tim() | ||
1818 | * callback. That, however, is already invoked under the | ||
1819 | * sta_lock to guarantee consistent and race-free update | ||
1820 | * of the tim bitmap in mac80211 and the driver. | ||
1821 | */ | ||
1822 | if (local->tim_in_locked_section) { | ||
1823 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1824 | } else { | ||
1825 | unsigned long flags; | ||
1826 | |||
1827 | spin_lock_irqsave(&local->sta_lock, flags); | ||
1828 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
1829 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1830 | } | ||
1825 | 1831 | ||
1826 | if (beacon->tail) | 1832 | if (beacon->tail) |
1827 | memcpy(skb_put(skb, beacon->tail_len), | 1833 | memcpy(skb_put(skb, beacon->tail_len), |
@@ -1965,7 +1971,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1965 | rcu_read_unlock(); | 1971 | rcu_read_unlock(); |
1966 | return NULL; | 1972 | return NULL; |
1967 | } | 1973 | } |
1968 | rcu_read_unlock(); | ||
1969 | 1974 | ||
1970 | if (bss->dtim_count != 0) | 1975 | if (bss->dtim_count != 0) |
1971 | return NULL; /* send buffered bc/mc only after DTIM beacon */ | 1976 | return NULL; /* send buffered bc/mc only after DTIM beacon */ |
@@ -2010,8 +2015,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2010 | skb = NULL; | 2015 | skb = NULL; |
2011 | } | 2016 | } |
2012 | 2017 | ||
2013 | if (sta) | 2018 | rcu_read_unlock(); |
2014 | sta_info_put(sta); | ||
2015 | 2019 | ||
2016 | return skb; | 2020 | return skb; |
2017 | } | 2021 | } |