aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-05-02 19:02:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-14 16:29:34 -0400
commit07346f81e87d6e4cca7ae9adfa711d0c61c87b56 (patch)
tree237450c49843e0e19afc79356240a891da64d9fa /net/mac80211/main.c
parent3434fbd39862d471c92b66c28cd449deea8e9f90 (diff)
mac80211: proper STA info locking
As discussed earlier, we can unify locking in struct sta_info and use just a single spinlock protecting all members of the structure that need protection. Many don't, but one of the especially bad ones is the 'flags' member that can currently be clobbered when RX and TX is being processed on different CPUs at the same time. Because having four spinlocks for different, mostly exclusive parts of a single structure is overkill, this patch also kills the ampdu and mesh plink spinlocks and uses just a single one for everything. Because none of the spinlocks are nested, this is safe. It remains to be seen whether or not we should make the sta flags use atomic bit operations instead, for now though this is a safe thing and using atomic operations instead will be very simple using the new static inline functions this patch introduces for accessing sta->flags. Since spin_lock_bh() is used with this lock, there shouldn't be any contention even if aggregation is enabled at around the same time as both requires frame transmission/reception which is in a bh context. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Tomas Winkler <tomasw@gmail.com> Cc: Ron Rindjunsky <ron.rindjunsky@intel.com> Cc: Luis Carlos Cobo <luisca@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r--net/mac80211/main.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 55e76117da9e..f277407f0f5a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -346,6 +346,7 @@ static int ieee80211_open(struct net_device *dev)
346 goto err_del_interface; 346 goto err_del_interface;
347 } 347 }
348 348
349 /* no locking required since STA is not live yet */
349 sta->flags |= WLAN_STA_AUTHORIZED; 350 sta->flags |= WLAN_STA_AUTHORIZED;
350 351
351 res = sta_info_insert(sta); 352 res = sta_info_insert(sta);
@@ -588,7 +589,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
588 return -ENOENT; 589 return -ENOENT;
589 } 590 }
590 591
591 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); 592 spin_lock_bh(&sta->lock);
592 593
593 /* we have tried too many times, receiver does not want A-MPDU */ 594 /* we have tried too many times, receiver does not want A-MPDU */
594 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { 595 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
@@ -691,7 +692,7 @@ start_ba_err:
691 spin_unlock_bh(&local->mdev->queue_lock); 692 spin_unlock_bh(&local->mdev->queue_lock);
692 ret = -EBUSY; 693 ret = -EBUSY;
693start_ba_exit: 694start_ba_exit:
694 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 695 spin_unlock_bh(&sta->lock);
695 rcu_read_unlock(); 696 rcu_read_unlock();
696 return ret; 697 return ret;
697} 698}
@@ -719,7 +720,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
719 720
720 /* check if the TID is in aggregation */ 721 /* check if the TID is in aggregation */
721 state = &sta->ampdu_mlme.tid_state_tx[tid]; 722 state = &sta->ampdu_mlme.tid_state_tx[tid];
722 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); 723 spin_lock_bh(&sta->lock);
723 724
724 if (*state != HT_AGG_STATE_OPERATIONAL) { 725 if (*state != HT_AGG_STATE_OPERATIONAL) {
725 ret = -ENOENT; 726 ret = -ENOENT;
@@ -749,7 +750,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
749 } 750 }
750 751
751stop_BA_exit: 752stop_BA_exit:
752 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 753 spin_unlock_bh(&sta->lock);
753 rcu_read_unlock(); 754 rcu_read_unlock();
754 return ret; 755 return ret;
755} 756}
@@ -778,12 +779,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
778 } 779 }
779 780
780 state = &sta->ampdu_mlme.tid_state_tx[tid]; 781 state = &sta->ampdu_mlme.tid_state_tx[tid];
781 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); 782 spin_lock_bh(&sta->lock);
782 783
783 if (!(*state & HT_ADDBA_REQUESTED_MSK)) { 784 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
784 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", 785 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
785 *state); 786 *state);
786 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 787 spin_unlock_bh(&sta->lock);
787 rcu_read_unlock(); 788 rcu_read_unlock();
788 return; 789 return;
789 } 790 }
@@ -796,7 +797,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
796 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); 797 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
797 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); 798 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
798 } 799 }
799 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 800 spin_unlock_bh(&sta->lock);
800 rcu_read_unlock(); 801 rcu_read_unlock();
801} 802}
802EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); 803EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -830,10 +831,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
830 } 831 }
831 state = &sta->ampdu_mlme.tid_state_tx[tid]; 832 state = &sta->ampdu_mlme.tid_state_tx[tid];
832 833
833 spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); 834 spin_lock_bh(&sta->lock);
834 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { 835 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
835 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); 836 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
836 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 837 spin_unlock_bh(&sta->lock);
837 rcu_read_unlock(); 838 rcu_read_unlock();
838 return; 839 return;
839 } 840 }
@@ -860,7 +861,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
860 sta->ampdu_mlme.addba_req_num[tid] = 0; 861 sta->ampdu_mlme.addba_req_num[tid] = 0;
861 kfree(sta->ampdu_mlme.tid_tx[tid]); 862 kfree(sta->ampdu_mlme.tid_tx[tid]);
862 sta->ampdu_mlme.tid_tx[tid] = NULL; 863 sta->ampdu_mlme.tid_tx[tid] = NULL;
863 spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); 864 spin_unlock_bh(&sta->lock);
864 865
865 rcu_read_unlock(); 866 rcu_read_unlock();
866} 867}
@@ -1315,7 +1316,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
1315 * packet. If the STA went to power save mode, this will happen 1316 * packet. If the STA went to power save mode, this will happen
1316 * happen when it wakes up for the next time. 1317 * happen when it wakes up for the next time.
1317 */ 1318 */
1318 sta->flags |= WLAN_STA_CLEAR_PS_FILT; 1319 set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
1319 1320
1320 /* 1321 /*
1321 * This code races in the following way: 1322 * This code races in the following way:
@@ -1347,7 +1348,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
1347 * can be unknown, for example with different interrupt status 1348 * can be unknown, for example with different interrupt status
1348 * bits. 1349 * bits.
1349 */ 1350 */
1350 if (sta->flags & WLAN_STA_PS && 1351 if (test_sta_flags(sta, WLAN_STA_PS) &&
1351 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { 1352 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
1352 ieee80211_remove_tx_extra(local, sta->key, skb, 1353 ieee80211_remove_tx_extra(local, sta->key, skb,
1353 &status->control); 1354 &status->control);
@@ -1355,7 +1356,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
1355 return; 1356 return;
1356 } 1357 }
1357 1358
1358 if (!(sta->flags & WLAN_STA_PS) && 1359 if (!test_sta_flags(sta, WLAN_STA_PS) &&
1359 !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { 1360 !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
1360 /* Software retry the packet once */ 1361 /* Software retry the packet once */
1361 status->control.flags |= IEEE80211_TXCTL_REQUEUE; 1362 status->control.flags |= IEEE80211_TXCTL_REQUEUE;
@@ -1370,7 +1371,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
1370 "queue_len=%d PS=%d @%lu\n", 1371 "queue_len=%d PS=%d @%lu\n",
1371 wiphy_name(local->hw.wiphy), 1372 wiphy_name(local->hw.wiphy),
1372 skb_queue_len(&sta->tx_filtered), 1373 skb_queue_len(&sta->tx_filtered),
1373 !!(sta->flags & WLAN_STA_PS), jiffies); 1374 !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
1374 dev_kfree_skb(skb); 1375 dev_kfree_skb(skb);
1375} 1376}
1376 1377
@@ -1399,7 +1400,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
1399 struct sta_info *sta; 1400 struct sta_info *sta;
1400 sta = sta_info_get(local, hdr->addr1); 1401 sta = sta_info_get(local, hdr->addr1);
1401 if (sta) { 1402 if (sta) {
1402 if (sta->flags & WLAN_STA_PS) { 1403 if (test_sta_flags(sta, WLAN_STA_PS)) {
1403 /* 1404 /*
1404 * The STA is in power save mode, so assume 1405 * The STA is in power save mode, so assume
1405 * that this TX packet failed because of that. 1406 * that this TX packet failed because of that.