aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com>2012-05-30 02:57:11 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2012-06-11 09:13:41 -0400
commit0faf745872f6d00afb318185e8fb181587974b5a (patch)
tree004a1d372b01b330869b99591762674351302b30 /drivers/net/wireless/ath/ath6kl
parentd154f32ebe3ffe9dea6ed0a91767883b1e7a6bc0 (diff)
ath6kl: Fix race in aggregation reorder logic
There are many places where tid data are accessed without the lock (rxtid->lock), this can lead to a race condition when the timeout handler for aggregatin reorder and the receive function are getting executed at the same time. Fix this race, but still there are races which can not be fixed without rewriting the whole aggregation reorder logic, for now fix the obvious ones. Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl')
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h12
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c12
2 files changed, 18 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 17a44fad859b..12441f7d9036 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -273,9 +273,15 @@ struct rxtid {
273 struct sk_buff_head q; 273 struct sk_buff_head q;
274 274
275 /* 275 /*
276 * FIXME: No clue what this should protect. Apparently it should 276 * lock mainly protects seq_next and hold_q. Movement of seq_next
277 * protect some of the fields above but they are also accessed 277 * needs to be protected between aggr_timeout() and
278 * without taking the lock. 278 * aggr_process_recv_frm(). hold_q will be holding the pending
279 * reorder frames and it's access should also be protected.
280 * Some of the other fields like hold_q_sz, win_sz and aggr are
281 * initialized/reset when receiving addba/delba req, also while
282 * deleting aggr state all the pending buffers are flushed before
283 * resetting these fields, so there should not be any race in accessing
284 * these fields.
279 */ 285 */
280 spinlock_t lock; 286 spinlock_t lock;
281}; 287};
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 67206aedea6c..974c51053a71 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
1036 rxtid = &agg_conn->rx_tid[tid]; 1036 rxtid = &agg_conn->rx_tid[tid];
1037 stats = &agg_conn->stat[tid]; 1037 stats = &agg_conn->stat[tid];
1038 1038
1039 spin_lock_bh(&rxtid->lock);
1039 idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); 1040 idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz);
1040 1041
1041 /* 1042 /*
@@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid,
1054 seq_end = seq_no ? seq_no : rxtid->seq_next; 1055 seq_end = seq_no ? seq_no : rxtid->seq_next;
1055 idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz); 1056 idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz);
1056 1057
1057 spin_lock_bh(&rxtid->lock);
1058
1059 do { 1058 do {
1060 node = &rxtid->hold_q[idx]; 1059 node = &rxtid->hold_q[idx];
1061 if ((order == 1) && (!node->skb)) 1060 if ((order == 1) && (!node->skb))
@@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
1127 ((end > extended_end) && (cur > extended_end) && 1126 ((end > extended_end) && (cur > extended_end) &&
1128 (cur < end))) { 1127 (cur < end))) {
1129 aggr_deque_frms(agg_conn, tid, 0, 0); 1128 aggr_deque_frms(agg_conn, tid, 0, 0);
1129 spin_lock_bh(&rxtid->lock);
1130 if (cur >= rxtid->hold_q_sz - 1) 1130 if (cur >= rxtid->hold_q_sz - 1)
1131 rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); 1131 rxtid->seq_next = cur - (rxtid->hold_q_sz - 1);
1132 else 1132 else
1133 rxtid->seq_next = ATH6KL_MAX_SEQ_NO - 1133 rxtid->seq_next = ATH6KL_MAX_SEQ_NO -
1134 (rxtid->hold_q_sz - 2 - cur); 1134 (rxtid->hold_q_sz - 2 - cur);
1135 spin_unlock_bh(&rxtid->lock);
1135 } else { 1136 } else {
1136 /* 1137 /*
1137 * Dequeue only those frames that are outside the 1138 * Dequeue only those frames that are outside the
@@ -1186,7 +1187,8 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
1186 1187
1187 if (agg_conn->timer_scheduled) 1188 if (agg_conn->timer_scheduled)
1188 rxtid->progress = true; 1189 rxtid->progress = true;
1189 else 1190 else {
1191 spin_lock_bh(&rxtid->lock);
1190 for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { 1192 for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) {
1191 if (rxtid->hold_q[idx].skb) { 1193 if (rxtid->hold_q[idx].skb) {
1192 /* 1194 /*
@@ -1204,6 +1206,8 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid,
1204 break; 1206 break;
1205 } 1207 }
1206 } 1208 }
1209 spin_unlock_bh(&rxtid->lock);
1210 }
1207 1211
1208 return is_queued; 1212 return is_queued;
1209} 1213}
@@ -1626,6 +1630,7 @@ static void aggr_timeout(unsigned long arg)
1626 rxtid = &aggr_conn->rx_tid[i]; 1630 rxtid = &aggr_conn->rx_tid[i];
1627 1631
1628 if (rxtid->aggr && rxtid->hold_q) { 1632 if (rxtid->aggr && rxtid->hold_q) {
1633 spin_lock_bh(&rxtid->lock);
1629 for (j = 0; j < rxtid->hold_q_sz; j++) { 1634 for (j = 0; j < rxtid->hold_q_sz; j++) {
1630 if (rxtid->hold_q[j].skb) { 1635 if (rxtid->hold_q[j].skb) {
1631 aggr_conn->timer_scheduled = true; 1636 aggr_conn->timer_scheduled = true;
@@ -1634,6 +1639,7 @@ static void aggr_timeout(unsigned long arg)
1634 break; 1639 break;
1635 } 1640 }
1636 } 1641 }
1642 spin_unlock_bh(&rxtid->lock);
1637 1643
1638 if (j >= rxtid->hold_q_sz) 1644 if (j >= rxtid->hold_q_sz)
1639 rxtid->timer_mon = false; 1645 rxtid->timer_mon = false;