aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-05-27 10:50:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-03 15:00:16 -0400
commitb83f4e15e65d94f6f56924b0b06a77a7ca2b4d8a (patch)
tree0b05ba16e7e2d53d6831e2a198a7a4c41836a752 /net
parent747cf5e924a469a15a454b88a813236460b30975 (diff)
mac80211: fix deadlock in sta->lock
This patch fixes a deadlock of sta->lock use, occurring while changing tx aggregation states, as dev_queue_xmit end up in new function test_and_clear_sta_flags that uses that lock thus leading to deadlock Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/main.c30
1 files changed, 17 insertions, 13 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 97d4a537ca2f..f79f6b9938a6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -589,8 +589,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
589 sta = sta_info_get(local, ra); 589 sta = sta_info_get(local, ra);
590 if (!sta) { 590 if (!sta) {
591 printk(KERN_DEBUG "Could not find the station\n"); 591 printk(KERN_DEBUG "Could not find the station\n");
592 rcu_read_unlock(); 592 ret = -ENOENT;
593 return -ENOENT; 593 goto exit;
594 } 594 }
595 595
596 spin_lock_bh(&sta->lock); 596 spin_lock_bh(&sta->lock);
@@ -598,7 +598,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
598 /* we have tried too many times, receiver does not want A-MPDU */ 598 /* we have tried too many times, receiver does not want A-MPDU */
599 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { 599 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
600 ret = -EBUSY; 600 ret = -EBUSY;
601 goto start_ba_exit; 601 goto err_unlock_sta;
602 } 602 }
603 603
604 state = &sta->ampdu_mlme.tid_state_tx[tid]; 604 state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -609,7 +609,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
609 "idle on tid %u\n", tid); 609 "idle on tid %u\n", tid);
610#endif /* CONFIG_MAC80211_HT_DEBUG */ 610#endif /* CONFIG_MAC80211_HT_DEBUG */
611 ret = -EAGAIN; 611 ret = -EAGAIN;
612 goto start_ba_exit; 612 goto err_unlock_sta;
613 } 613 }
614 614
615 /* prepare A-MPDU MLME for Tx aggregation */ 615 /* prepare A-MPDU MLME for Tx aggregation */
@@ -620,7 +620,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
620 printk(KERN_ERR "allocate tx mlme to tid %d failed\n", 620 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
621 tid); 621 tid);
622 ret = -ENOMEM; 622 ret = -ENOMEM;
623 goto start_ba_exit; 623 goto err_unlock_sta;
624 } 624 }
625 /* Tx timer */ 625 /* Tx timer */
626 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = 626 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
@@ -643,7 +643,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
643 printk(KERN_DEBUG "BA request denied - queue unavailable for" 643 printk(KERN_DEBUG "BA request denied - queue unavailable for"
644 " tid %d\n", tid); 644 " tid %d\n", tid);
645#endif /* CONFIG_MAC80211_HT_DEBUG */ 645#endif /* CONFIG_MAC80211_HT_DEBUG */
646 goto start_ba_err; 646 goto err_unlock_queue;
647 } 647 }
648 sdata = sta->sdata; 648 sdata = sta->sdata;
649 649
@@ -665,12 +665,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
665 " tid %d\n", tid); 665 " tid %d\n", tid);
666#endif /* CONFIG_MAC80211_HT_DEBUG */ 666#endif /* CONFIG_MAC80211_HT_DEBUG */
667 *state = HT_AGG_STATE_IDLE; 667 *state = HT_AGG_STATE_IDLE;
668 goto start_ba_err; 668 goto err_unlock_queue;
669 } 669 }
670 670
671 /* Will put all the packets in the new SW queue */ 671 /* Will put all the packets in the new SW queue */
672 ieee80211_requeue(local, ieee802_1d_to_ac[tid]); 672 ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
673 spin_unlock_bh(&local->mdev->queue_lock); 673 spin_unlock_bh(&local->mdev->queue_lock);
674 spin_unlock_bh(&sta->lock);
674 675
675 /* send an addBA request */ 676 /* send an addBA request */
676 sta->ampdu_mlme.dialog_token_allocator++; 677 sta->ampdu_mlme.dialog_token_allocator++;
@@ -678,25 +679,26 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
678 sta->ampdu_mlme.dialog_token_allocator; 679 sta->ampdu_mlme.dialog_token_allocator;
679 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; 680 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
680 681
682
681 ieee80211_send_addba_request(sta->sdata->dev, ra, tid, 683 ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
682 sta->ampdu_mlme.tid_tx[tid]->dialog_token, 684 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
683 sta->ampdu_mlme.tid_tx[tid]->ssn, 685 sta->ampdu_mlme.tid_tx[tid]->ssn,
684 0x40, 5000); 686 0x40, 5000);
685
686 /* activate the timer for the recipient's addBA response */ 687 /* activate the timer for the recipient's addBA response */
687 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = 688 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
688 jiffies + ADDBA_RESP_INTERVAL; 689 jiffies + ADDBA_RESP_INTERVAL;
689 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); 690 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
690 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); 691 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
691 goto start_ba_exit; 692 goto exit;
692 693
693start_ba_err: 694err_unlock_queue:
694 kfree(sta->ampdu_mlme.tid_tx[tid]); 695 kfree(sta->ampdu_mlme.tid_tx[tid]);
695 sta->ampdu_mlme.tid_tx[tid] = NULL; 696 sta->ampdu_mlme.tid_tx[tid] = NULL;
696 spin_unlock_bh(&local->mdev->queue_lock); 697 spin_unlock_bh(&local->mdev->queue_lock);
697 ret = -EBUSY; 698 ret = -EBUSY;
698start_ba_exit: 699err_unlock_sta:
699 spin_unlock_bh(&sta->lock); 700 spin_unlock_bh(&sta->lock);
701exit:
700 rcu_read_unlock(); 702 rcu_read_unlock();
701 return ret; 703 return ret;
702} 704}
@@ -835,10 +837,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
835 } 837 }
836 state = &sta->ampdu_mlme.tid_state_tx[tid]; 838 state = &sta->ampdu_mlme.tid_state_tx[tid];
837 839
838 spin_lock_bh(&sta->lock); 840 /* NOTE: no need to use sta->lock in this state check, as
841 * ieee80211_stop_tx_ba_session will let only
842 * one stop call to pass through per sta/tid */
839 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { 843 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
840 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); 844 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
841 spin_unlock_bh(&sta->lock);
842 rcu_read_unlock(); 845 rcu_read_unlock();
843 return; 846 return;
844 } 847 }
@@ -861,6 +864,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
861 * ieee80211_wake_queue is not used here as this queue is not 864 * ieee80211_wake_queue is not used here as this queue is not
862 * necessarily stopped */ 865 * necessarily stopped */
863 netif_schedule(local->mdev); 866 netif_schedule(local->mdev);
867 spin_lock_bh(&sta->lock);
864 *state = HT_AGG_STATE_IDLE; 868 *state = HT_AGG_STATE_IDLE;
865 sta->ampdu_mlme.addba_req_num[tid] = 0; 869 sta->ampdu_mlme.addba_req_num[tid] = 0;
866 kfree(sta->ampdu_mlme.tid_tx[tid]); 870 kfree(sta->ampdu_mlme.tid_tx[tid]);