aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/agg-tx.c229
-rw-r--r--net/mac80211/debugfs_sta.c8
-rw-r--r--net/mac80211/ht.c9
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c2
-rw-r--r--net/mac80211/sta_info.c12
-rw-r--r--net/mac80211/sta_info.h33
-rw-r--r--net/mac80211/tx.c88
8 files changed, 206 insertions, 177 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c7b7ac40316a..7d8656d51c6b 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -125,25 +125,42 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
125 ieee80211_tx_skb(sdata, skb); 125 ieee80211_tx_skb(sdata, skb);
126} 126}
127 127
128int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, 128static void kfree_tid_tx(struct rcu_head *rcu_head)
129 enum ieee80211_back_parties initiator) 129{
130 struct tid_ampdu_tx *tid_tx =
131 container_of(rcu_head, struct tid_ampdu_tx, rcu_head);
132
133 kfree(tid_tx);
134}
135
136static int ___ieee80211_stop_tx_ba_session(
137 struct sta_info *sta, u16 tid,
138 enum ieee80211_back_parties initiator)
130{ 139{
131 struct ieee80211_local *local = sta->local; 140 struct ieee80211_local *local = sta->local;
141 struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
132 int ret; 142 int ret;
133 u8 *state; 143
144 lockdep_assert_held(&sta->lock);
145
146 if (WARN_ON(!tid_tx))
147 return -ENOENT;
134 148
135#ifdef CONFIG_MAC80211_HT_DEBUG 149#ifdef CONFIG_MAC80211_HT_DEBUG
136 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", 150 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
137 sta->sta.addr, tid); 151 sta->sta.addr, tid);
138#endif /* CONFIG_MAC80211_HT_DEBUG */ 152#endif /* CONFIG_MAC80211_HT_DEBUG */
139 153
140 state = &sta->ampdu_mlme.tid_state_tx[tid]; 154 set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
141 155
142 if (*state == HT_AGG_STATE_OPERATIONAL) 156 /*
143 sta->ampdu_mlme.addba_req_num[tid] = 0; 157 * After this packets are no longer handed right through
158 * to the driver but are put onto tid_tx->pending instead,
159 * with locking to ensure proper access.
160 */
161 clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
144 162
145 *state = HT_AGG_STATE_REQ_STOP_BA_MSK | 163 tid_tx->stop_initiator = initiator;
146 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
147 164
148 ret = drv_ampdu_action(local, sta->sdata, 165 ret = drv_ampdu_action(local, sta->sdata,
149 IEEE80211_AMPDU_TX_STOP, 166 IEEE80211_AMPDU_TX_STOP,
@@ -174,15 +191,13 @@ static void sta_addba_resp_timer_expired(unsigned long data)
174 u16 tid = *(u8 *)data; 191 u16 tid = *(u8 *)data;
175 struct sta_info *sta = container_of((void *)data, 192 struct sta_info *sta = container_of((void *)data,
176 struct sta_info, timer_to_tid[tid]); 193 struct sta_info, timer_to_tid[tid]);
177 u8 *state; 194 struct tid_ampdu_tx *tid_tx;
178
179 state = &sta->ampdu_mlme.tid_state_tx[tid];
180 195
181 /* check if the TID waits for addBA response */ 196 /* check if the TID waits for addBA response */
182 spin_lock_bh(&sta->lock); 197 spin_lock_bh(&sta->lock);
183 if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK | 198 tid_tx = sta->ampdu_mlme.tid_tx[tid];
184 HT_AGG_STATE_REQ_STOP_BA_MSK)) != 199 if (!tid_tx ||
185 HT_ADDBA_REQUESTED_MSK) { 200 test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
186 spin_unlock_bh(&sta->lock); 201 spin_unlock_bh(&sta->lock);
187#ifdef CONFIG_MAC80211_HT_DEBUG 202#ifdef CONFIG_MAC80211_HT_DEBUG
188 printk(KERN_DEBUG "timer expired on tid %d but we are not " 203 printk(KERN_DEBUG "timer expired on tid %d but we are not "
@@ -210,7 +225,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
210 struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 225 struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
211 struct ieee80211_sub_if_data *sdata = sta->sdata; 226 struct ieee80211_sub_if_data *sdata = sta->sdata;
212 struct ieee80211_local *local = sdata->local; 227 struct ieee80211_local *local = sdata->local;
213 u8 *state; 228 struct tid_ampdu_tx *tid_tx;
214 int ret = 0; 229 int ret = 0;
215 u16 start_seq_num; 230 u16 start_seq_num;
216 231
@@ -256,9 +271,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
256 goto err_unlock_sta; 271 goto err_unlock_sta;
257 } 272 }
258 273
259 state = &sta->ampdu_mlme.tid_state_tx[tid]; 274 tid_tx = sta->ampdu_mlme.tid_tx[tid];
260 /* check if the TID is not in aggregation flow already */ 275 /* check if the TID is not in aggregation flow already */
261 if (*state != HT_AGG_STATE_IDLE) { 276 if (tid_tx) {
262#ifdef CONFIG_MAC80211_HT_DEBUG 277#ifdef CONFIG_MAC80211_HT_DEBUG
263 printk(KERN_DEBUG "BA request denied - session is not " 278 printk(KERN_DEBUG "BA request denied - session is not "
264 "idle on tid %u\n", tid); 279 "idle on tid %u\n", tid);
@@ -279,9 +294,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
279 IEEE80211_QUEUE_STOP_REASON_AGGREGATION); 294 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
280 295
281 /* prepare A-MPDU MLME for Tx aggregation */ 296 /* prepare A-MPDU MLME for Tx aggregation */
282 sta->ampdu_mlme.tid_tx[tid] = 297 tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
283 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); 298 if (!tid_tx) {
284 if (!sta->ampdu_mlme.tid_tx[tid]) {
285#ifdef CONFIG_MAC80211_HT_DEBUG 299#ifdef CONFIG_MAC80211_HT_DEBUG
286 if (net_ratelimit()) 300 if (net_ratelimit())
287 printk(KERN_ERR "allocate tx mlme to tid %d failed\n", 301 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
@@ -291,33 +305,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
291 goto err_wake_queue; 305 goto err_wake_queue;
292 } 306 }
293 307
294 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending); 308 skb_queue_head_init(&tid_tx->pending);
295 309
296 /* Tx timer */ 310 /* Tx timer */
297 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = 311 tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
298 sta_addba_resp_timer_expired; 312 tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
299 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = 313 init_timer(&tid_tx->addba_resp_timer);
300 (unsigned long)&sta->timer_to_tid[tid];
301 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
302
303 /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
304 * call back right away, it must see that the flow has begun */
305 *state |= HT_ADDBA_REQUESTED_MSK;
306 314
307 start_seq_num = sta->tid_seq[tid] >> 4; 315 start_seq_num = sta->tid_seq[tid] >> 4;
308 316
309 ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, 317 ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
310 pubsta, tid, &start_seq_num); 318 pubsta, tid, &start_seq_num);
311
312 if (ret) { 319 if (ret) {
313#ifdef CONFIG_MAC80211_HT_DEBUG 320#ifdef CONFIG_MAC80211_HT_DEBUG
314 printk(KERN_DEBUG "BA request denied - HW unavailable for" 321 printk(KERN_DEBUG "BA request denied - HW unavailable for"
315 " tid %d\n", tid); 322 " tid %d\n", tid);
316#endif /* CONFIG_MAC80211_HT_DEBUG */ 323#endif /* CONFIG_MAC80211_HT_DEBUG */
317 *state = HT_AGG_STATE_IDLE;
318 goto err_free; 324 goto err_free;
319 } 325 }
320 326
327 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
328
321 /* Driver vetoed or OKed, but we can take packets again now */ 329 /* Driver vetoed or OKed, but we can take packets again now */
322 ieee80211_wake_queue_by_reason( 330 ieee80211_wake_queue_by_reason(
323 &local->hw, ieee80211_ac_from_tid(tid), 331 &local->hw, ieee80211_ac_from_tid(tid),
@@ -325,32 +333,30 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
325 333
326 spin_unlock(&local->ampdu_lock); 334 spin_unlock(&local->ampdu_lock);
327 335
336 /* activate the timer for the recipient's addBA response */
337 tid_tx->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL;
338 add_timer(&tid_tx->addba_resp_timer);
339#ifdef CONFIG_MAC80211_HT_DEBUG
340 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
341#endif
342
328 /* prepare tid data */ 343 /* prepare tid data */
329 sta->ampdu_mlme.dialog_token_allocator++; 344 sta->ampdu_mlme.dialog_token_allocator++;
330 sta->ampdu_mlme.tid_tx[tid]->dialog_token = 345 tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
331 sta->ampdu_mlme.dialog_token_allocator; 346 tid_tx->ssn = start_seq_num;
332 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; 347
348 sta->ampdu_mlme.addba_req_num[tid]++;
333 349
334 spin_unlock_bh(&sta->lock); 350 spin_unlock_bh(&sta->lock);
335 351
336 /* send AddBA request */ 352 /* send AddBA request */
337 ieee80211_send_addba_request(sdata, pubsta->addr, tid, 353 ieee80211_send_addba_request(sdata, pubsta->addr, tid,
338 sta->ampdu_mlme.tid_tx[tid]->dialog_token, 354 tid_tx->dialog_token, tid_tx->ssn,
339 sta->ampdu_mlme.tid_tx[tid]->ssn,
340 0x40, 5000); 355 0x40, 5000);
341 sta->ampdu_mlme.addba_req_num[tid]++;
342 /* activate the timer for the recipient's addBA response */
343 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
344 jiffies + ADDBA_RESP_INTERVAL;
345 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
346#ifdef CONFIG_MAC80211_HT_DEBUG
347 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
348#endif
349 return 0; 356 return 0;
350 357
351 err_free: 358 err_free:
352 kfree(sta->ampdu_mlme.tid_tx[tid]); 359 kfree(tid_tx);
353 sta->ampdu_mlme.tid_tx[tid] = NULL;
354 err_wake_queue: 360 err_wake_queue:
355 ieee80211_wake_queue_by_reason( 361 ieee80211_wake_queue_by_reason(
356 &local->hw, ieee80211_ac_from_tid(tid), 362 &local->hw, ieee80211_ac_from_tid(tid),
@@ -368,7 +374,8 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
368 * local->ampdu_lock across both calls. 374 * local->ampdu_lock across both calls.
369 */ 375 */
370static void ieee80211_agg_splice_packets(struct ieee80211_local *local, 376static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
371 struct sta_info *sta, u16 tid) 377 struct tid_ampdu_tx *tid_tx,
378 u16 tid)
372{ 379{
373 unsigned long flags; 380 unsigned long flags;
374 u16 queue = ieee80211_ac_from_tid(tid); 381 u16 queue = ieee80211_ac_from_tid(tid);
@@ -377,31 +384,23 @@ static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
377 &local->hw, queue, 384 &local->hw, queue,
378 IEEE80211_QUEUE_STOP_REASON_AGGREGATION); 385 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
379 386
380 if (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)) 387 if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
381 return; 388 " from the pending queue\n", tid))
382
383 if (WARN(!sta->ampdu_mlme.tid_tx[tid],
384 "TID %d gone but expected when splicing aggregates from"
385 "the pending queue\n", tid))
386 return; 389 return;
387 390
388 if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { 391 if (!skb_queue_empty(&tid_tx->pending)) {
389 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 392 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
390 /* copy over remaining packets */ 393 /* copy over remaining packets */
391 skb_queue_splice_tail_init( 394 skb_queue_splice_tail_init(&tid_tx->pending,
392 &sta->ampdu_mlme.tid_tx[tid]->pending, 395 &local->pending[queue]);
393 &local->pending[queue]);
394 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 396 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
395 } 397 }
396} 398}
397 399
398static void ieee80211_agg_splice_finish(struct ieee80211_local *local, 400static void ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid)
399 struct sta_info *sta, u16 tid)
400{ 401{
401 u16 queue = ieee80211_ac_from_tid(tid);
402
403 ieee80211_wake_queue_by_reason( 402 ieee80211_wake_queue_by_reason(
404 &local->hw, queue, 403 &local->hw, ieee80211_ac_from_tid(tid),
405 IEEE80211_QUEUE_STOP_REASON_AGGREGATION); 404 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
406} 405}
407 406
@@ -409,19 +408,21 @@ static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
409static void ieee80211_agg_tx_operational(struct ieee80211_local *local, 408static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
410 struct sta_info *sta, u16 tid) 409 struct sta_info *sta, u16 tid)
411{ 410{
411 lockdep_assert_held(&sta->lock);
412
412#ifdef CONFIG_MAC80211_HT_DEBUG 413#ifdef CONFIG_MAC80211_HT_DEBUG
413 printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); 414 printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
414#endif 415#endif
415 416
416 spin_lock(&local->ampdu_lock); 417 spin_lock(&local->ampdu_lock);
417 ieee80211_agg_splice_packets(local, sta, tid); 418 ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
418 /* 419 /*
419 * NB: we rely on sta->lock being taken in the TX 420 * Now mark as operational. This will be visible
420 * processing here when adding to the pending queue, 421 * in the TX path, and lets it go lock-free in
421 * otherwise we could only change the state of the 422 * the common case.
422 * session to OPERATIONAL _here_.
423 */ 423 */
424 ieee80211_agg_splice_finish(local, sta, tid); 424 set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
425 ieee80211_agg_splice_finish(local, tid);
425 spin_unlock(&local->ampdu_lock); 426 spin_unlock(&local->ampdu_lock);
426 427
427 drv_ampdu_action(local, sta->sdata, 428 drv_ampdu_action(local, sta->sdata,
@@ -434,7 +435,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
434 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 435 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
435 struct ieee80211_local *local = sdata->local; 436 struct ieee80211_local *local = sdata->local;
436 struct sta_info *sta; 437 struct sta_info *sta;
437 u8 *state; 438 struct tid_ampdu_tx *tid_tx;
438 439
439 trace_api_start_tx_ba_cb(sdata, ra, tid); 440 trace_api_start_tx_ba_cb(sdata, ra, tid);
440 441
@@ -456,25 +457,22 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
456 return; 457 return;
457 } 458 }
458 459
459 state = &sta->ampdu_mlme.tid_state_tx[tid];
460 spin_lock_bh(&sta->lock); 460 spin_lock_bh(&sta->lock);
461 tid_tx = sta->ampdu_mlme.tid_tx[tid];
461 462
462 if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) { 463 if (WARN_ON(!tid_tx)) {
463#ifdef CONFIG_MAC80211_HT_DEBUG 464#ifdef CONFIG_MAC80211_HT_DEBUG
464 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", 465 printk(KERN_DEBUG "addBA was not requested!\n");
465 *state);
466#endif 466#endif
467 spin_unlock_bh(&sta->lock); 467 spin_unlock_bh(&sta->lock);
468 rcu_read_unlock(); 468 rcu_read_unlock();
469 return; 469 return;
470 } 470 }
471 471
472 if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK)) 472 if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
473 goto out; 473 goto out;
474 474
475 *state |= HT_ADDBA_DRV_READY_MSK; 475 if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
476
477 if (*state == HT_AGG_STATE_OPERATIONAL)
478 ieee80211_agg_tx_operational(local, sta, tid); 476 ieee80211_agg_tx_operational(local, sta, tid);
479 477
480 out: 478 out:
@@ -512,14 +510,14 @@ EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
512int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, 510int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
513 enum ieee80211_back_parties initiator) 511 enum ieee80211_back_parties initiator)
514{ 512{
515 u8 *state; 513 struct tid_ampdu_tx *tid_tx;
516 int ret; 514 int ret;
517 515
518 /* check if the TID is in aggregation */
519 state = &sta->ampdu_mlme.tid_state_tx[tid];
520 spin_lock_bh(&sta->lock); 516 spin_lock_bh(&sta->lock);
517 tid_tx = sta->ampdu_mlme.tid_tx[tid];
521 518
522 if (*state != HT_AGG_STATE_OPERATIONAL) { 519 /* check if the TID is in aggregation */
520 if (!tid_tx || !test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
523 ret = -ENOENT; 521 ret = -ENOENT;
524 goto unlock; 522 goto unlock;
525 } 523 }
@@ -554,7 +552,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
554 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 552 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
555 struct ieee80211_local *local = sdata->local; 553 struct ieee80211_local *local = sdata->local;
556 struct sta_info *sta; 554 struct sta_info *sta;
557 u8 *state; 555 struct tid_ampdu_tx *tid_tx;
558 556
559 trace_api_stop_tx_ba_cb(sdata, ra, tid); 557 trace_api_stop_tx_ba_cb(sdata, ra, tid);
560 558
@@ -580,39 +578,45 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
580 rcu_read_unlock(); 578 rcu_read_unlock();
581 return; 579 return;
582 } 580 }
583 state = &sta->ampdu_mlme.tid_state_tx[tid];
584 581
585 /* NOTE: no need to use sta->lock in this state check, as 582 spin_lock_bh(&sta->lock);
586 * ieee80211_stop_tx_ba_session will let only one stop call to 583 tid_tx = sta->ampdu_mlme.tid_tx[tid];
587 * pass through per sta/tid 584
588 */ 585 if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
589 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
590#ifdef CONFIG_MAC80211_HT_DEBUG 586#ifdef CONFIG_MAC80211_HT_DEBUG
591 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); 587 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
592#endif 588#endif
589 spin_unlock_bh(&sta->lock);
593 rcu_read_unlock(); 590 rcu_read_unlock();
594 return; 591 return;
595 } 592 }
596 593
597 if (*state & HT_AGG_STATE_INITIATOR_MSK) 594 if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR)
598 ieee80211_send_delba(sta->sdata, ra, tid, 595 ieee80211_send_delba(sta->sdata, ra, tid,
599 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); 596 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
600 597
601 spin_lock_bh(&sta->lock); 598 /*
602 spin_lock(&local->ampdu_lock); 599 * When we get here, the TX path will not be lockless any more wrt.
600 * aggregation, since the OPERATIONAL bit has long been cleared.
601 * Thus it will block on getting the lock, if it occurs. So if we
602 * stop the queue now, we will not get any more packets, and any
603 * that might be being processed will wait for us here, thereby
604 * guaranteeing that no packets go to the tid_tx pending queue any
605 * more.
606 */
603 607
604 ieee80211_agg_splice_packets(local, sta, tid); 608 spin_lock(&local->ampdu_lock);
609 ieee80211_agg_splice_packets(local, tid_tx, tid);
605 610
606 *state = HT_AGG_STATE_IDLE; 611 /* future packets must not find the tid_tx struct any more */
607 /* from now on packets are no longer put onto sta->pending */ 612 rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
608 kfree(sta->ampdu_mlme.tid_tx[tid]);
609 sta->ampdu_mlme.tid_tx[tid] = NULL;
610 613
611 ieee80211_agg_splice_finish(local, sta, tid); 614 ieee80211_agg_splice_finish(local, tid);
612 615
616 call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
613 spin_unlock(&local->ampdu_lock); 617 spin_unlock(&local->ampdu_lock);
614 spin_unlock_bh(&sta->lock);
615 618
619 spin_unlock_bh(&sta->lock);
616 rcu_read_unlock(); 620 rcu_read_unlock();
617} 621}
618EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); 622EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
@@ -649,40 +653,41 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
649 struct ieee80211_mgmt *mgmt, 653 struct ieee80211_mgmt *mgmt,
650 size_t len) 654 size_t len)
651{ 655{
656 struct tid_ampdu_tx *tid_tx;
652 u16 capab, tid; 657 u16 capab, tid;
653 u8 *state;
654 658
655 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); 659 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
656 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; 660 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
657 661
658 state = &sta->ampdu_mlme.tid_state_tx[tid];
659
660 spin_lock_bh(&sta->lock); 662 spin_lock_bh(&sta->lock);
661 663
662 if (!(*state & HT_ADDBA_REQUESTED_MSK)) 664 tid_tx = sta->ampdu_mlme.tid_tx[tid];
665
666 if (!tid_tx)
663 goto out; 667 goto out;
664 668
665 if (mgmt->u.action.u.addba_resp.dialog_token != 669 if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
666 sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
667#ifdef CONFIG_MAC80211_HT_DEBUG 670#ifdef CONFIG_MAC80211_HT_DEBUG
668 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); 671 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
669#endif /* CONFIG_MAC80211_HT_DEBUG */ 672#endif
670 goto out; 673 goto out;
671 } 674 }
672 675
673 del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); 676 del_timer(&tid_tx->addba_resp_timer);
674 677
675#ifdef CONFIG_MAC80211_HT_DEBUG 678#ifdef CONFIG_MAC80211_HT_DEBUG
676 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); 679 printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
677#endif /* CONFIG_MAC80211_HT_DEBUG */ 680#endif
678 681
679 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) 682 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
680 == WLAN_STATUS_SUCCESS) { 683 == WLAN_STATUS_SUCCESS) {
681 u8 curstate = *state; 684 if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
682 685 &tid_tx->state)) {
683 *state |= HT_ADDBA_RECEIVED_MSK; 686 /* ignore duplicate response */
687 goto out;
688 }
684 689
685 if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL) 690 if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
686 ieee80211_agg_tx_operational(local, sta, tid); 691 ieee80211_agg_tx_operational(local, sta, tid);
687 692
688 sta->ampdu_mlme.addba_req_num[tid] = 0; 693 sta->ampdu_mlme.addba_req_num[tid] = 0;
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 95c1ea47ad35..8a74ffb36ad4 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -134,15 +134,15 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
134 sta->ampdu_mlme.tid_rx[i]->ssn : 0); 134 sta->ampdu_mlme.tid_rx[i]->ssn : 0);
135 135
136 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", 136 p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
137 sta->ampdu_mlme.tid_state_tx[i]); 137 !!sta->ampdu_mlme.tid_tx[i]);
138 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", 138 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
139 sta->ampdu_mlme.tid_state_tx[i] ? 139 sta->ampdu_mlme.tid_tx[i] ?
140 sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); 140 sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
141 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", 141 p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
142 sta->ampdu_mlme.tid_state_tx[i] ? 142 sta->ampdu_mlme.tid_tx[i] ?
143 sta->ampdu_mlme.tid_tx[i]->ssn : 0); 143 sta->ampdu_mlme.tid_tx[i]->ssn : 0);
144 p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", 144 p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
145 sta->ampdu_mlme.tid_state_tx[i] ? 145 sta->ampdu_mlme.tid_tx[i] ?
146 skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); 146 skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
147 p += scnprintf(p, sizeof(buf) + buf - p, "\n"); 147 p += scnprintf(p, sizeof(buf) + buf - p, "\n");
148 } 148 }
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2ab106a0a491..1af173ed2d5e 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -176,13 +176,8 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
176 176
177 if (initiator == WLAN_BACK_INITIATOR) 177 if (initiator == WLAN_BACK_INITIATOR)
178 __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0); 178 __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
179 else { /* WLAN_BACK_RECIPIENT */ 179 else
180 spin_lock_bh(&sta->lock); 180 __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_RECIPIENT);
181 if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
182 ___ieee80211_stop_tx_ba_session(sta, tid,
183 WLAN_BACK_RECIPIENT);
184 spin_unlock_bh(&sta->lock);
185 }
186} 181}
187 182
188int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, 183int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index bafe610dcf77..71bdd8b3c3f4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1119,8 +1119,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
1119 1119
1120int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, 1120int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
1121 enum ieee80211_back_parties initiator); 1121 enum ieee80211_back_parties initiator);
1122int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
1123 enum ieee80211_back_parties initiator);
1124 1122
1125/* Spectrum management */ 1123/* Spectrum management */
1126void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, 1124void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index c23f08251da4..7a04951fcb1f 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -365,7 +365,7 @@ minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, stru
365 return; 365 return;
366 366
367 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 367 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
368 if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE)) 368 if (likely(sta->ampdu_mlme.tid_tx[tid]))
369 return; 369 return;
370 370
371 ieee80211_start_tx_ba_session(pubsta, tid); 371 ieee80211_start_tx_ba_session(pubsta, tid);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index c426c572d984..06d8e00a2537 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -246,14 +246,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
246 } 246 }
247 247
248 for (i = 0; i < STA_TID_NUM; i++) { 248 for (i = 0; i < STA_TID_NUM; i++) {
249 /* timer_to_tid must be initialized with identity mapping to 249 /*
250 * enable session_timer's data differentiation. refer to 250 * timer_to_tid must be initialized with identity mapping
251 * sta_rx_agg_session_timer_expired for useage */ 251 * to enable session_timer's data differentiation. See
252 * sta_rx_agg_session_timer_expired for usage.
253 */
252 sta->timer_to_tid[i] = i; 254 sta->timer_to_tid[i] = i;
253 /* tx */
254 sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
255 sta->ampdu_mlme.tid_tx[i] = NULL;
256 sta->ampdu_mlme.addba_req_num[i] = 0;
257 } 255 }
258 skb_queue_head_init(&sta->ps_tx_buf); 256 skb_queue_head_init(&sta->ps_tx_buf);
259 skb_queue_head_init(&sta->tx_filtered); 257 skb_queue_head_init(&sta->tx_filtered);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 16864a6045b4..05278e6288c9 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -61,33 +61,40 @@ enum ieee80211_sta_info_flags {
61 61
62#define STA_TID_NUM 16 62#define STA_TID_NUM 16
63#define ADDBA_RESP_INTERVAL HZ 63#define ADDBA_RESP_INTERVAL HZ
64#define HT_AGG_MAX_RETRIES (0x3) 64#define HT_AGG_MAX_RETRIES 0x3
65 65
66#define HT_AGG_STATE_INITIATOR_SHIFT (4) 66#define HT_AGG_STATE_DRV_READY 0
67 67#define HT_AGG_STATE_RESPONSE_RECEIVED 1
68#define HT_ADDBA_REQUESTED_MSK BIT(0) 68#define HT_AGG_STATE_OPERATIONAL 2
69#define HT_ADDBA_DRV_READY_MSK BIT(1) 69#define HT_AGG_STATE_STOPPING 3
70#define HT_ADDBA_RECEIVED_MSK BIT(2)
71#define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3)
72#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT)
73#define HT_AGG_STATE_IDLE (0x0)
74#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \
75 HT_ADDBA_DRV_READY_MSK | \
76 HT_ADDBA_RECEIVED_MSK)
77 70
78/** 71/**
79 * struct tid_ampdu_tx - TID aggregation information (Tx). 72 * struct tid_ampdu_tx - TID aggregation information (Tx).
80 * 73 *
74 * @rcu_head: rcu head for freeing structure
81 * @addba_resp_timer: timer for peer's response to addba request 75 * @addba_resp_timer: timer for peer's response to addba request
82 * @pending: pending frames queue -- use sta's spinlock to protect 76 * @pending: pending frames queue -- use sta's spinlock to protect
83 * @ssn: Starting Sequence Number expected to be aggregated. 77 * @ssn: Starting Sequence Number expected to be aggregated.
84 * @dialog_token: dialog token for aggregation session 78 * @dialog_token: dialog token for aggregation session
79 * @state: session state (see above)
80 * @stop_initiator: initiator of a session stop
81 *
82 * This structure is protected by RCU and the per-station
83 * spinlock. Assignments to the array holding it must hold
84 * the spinlock, only the TX path can access it under RCU
85 * lock-free if, and only if, the state has the flag
86 * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path
87 * must also acquire the spinlock and re-check the state,
88 * see comments in the tx code touching it.
85 */ 89 */
86struct tid_ampdu_tx { 90struct tid_ampdu_tx {
91 struct rcu_head rcu_head;
87 struct timer_list addba_resp_timer; 92 struct timer_list addba_resp_timer;
88 struct sk_buff_head pending; 93 struct sk_buff_head pending;
94 unsigned long state;
89 u16 ssn; 95 u16 ssn;
90 u8 dialog_token; 96 u8 dialog_token;
97 u8 stop_initiator;
91}; 98};
92 99
93/** 100/**
@@ -129,7 +136,6 @@ struct tid_ampdu_rx {
129 * struct sta_ampdu_mlme - STA aggregation information. 136 * struct sta_ampdu_mlme - STA aggregation information.
130 * 137 *
131 * @tid_rx: aggregation info for Rx per TID -- RCU protected 138 * @tid_rx: aggregation info for Rx per TID -- RCU protected
132 * @tid_state_tx: TID's state in Tx session state machine.
133 * @tid_tx: aggregation info for Tx per TID 139 * @tid_tx: aggregation info for Tx per TID
134 * @addba_req_num: number of times addBA request has been sent. 140 * @addba_req_num: number of times addBA request has been sent.
135 * @dialog_token_allocator: dialog token enumerator for each new session; 141 * @dialog_token_allocator: dialog token enumerator for each new session;
@@ -138,7 +144,6 @@ struct sta_ampdu_mlme {
138 /* rx */ 144 /* rx */
139 struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; 145 struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
140 /* tx */ 146 /* tx */
141 u8 tid_state_tx[STA_TID_NUM];
142 struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; 147 struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
143 u8 addba_req_num[STA_TID_NUM]; 148 u8 addba_req_num[STA_TID_NUM];
144 u8 dialog_token_allocator; 149 u8 dialog_token_allocator;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 680bcb7093db..7bf1f9c9ea34 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1092,6 +1092,54 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
1092 return true; 1092 return true;
1093} 1093}
1094 1094
1095static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
1096 struct sk_buff *skb,
1097 struct ieee80211_tx_info *info,
1098 struct tid_ampdu_tx *tid_tx,
1099 int tid)
1100{
1101 bool queued = false;
1102
1103 if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1104 info->flags |= IEEE80211_TX_CTL_AMPDU;
1105 } else {
1106 spin_lock(&tx->sta->lock);
1107 /*
1108 * Need to re-check now, because we may get here
1109 *
1110 * 1) in the window during which the setup is actually
1111 * already done, but not marked yet because not all
1112 * packets are spliced over to the driver pending
1113 * queue yet -- if this happened we acquire the lock
1114 * either before or after the splice happens, but
1115 * need to recheck which of these cases happened.
1116 *
1117 * 2) during session teardown, if the OPERATIONAL bit
1118 * was cleared due to the teardown but the pointer
1119 * hasn't been assigned NULL yet (or we loaded it
1120 * before it was assigned) -- in this case it may
1121 * now be NULL which means we should just let the
1122 * packet pass through because splicing the frames
1123 * back is already done.
1124 */
1125 tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
1126
1127 if (!tid_tx) {
1128 /* do nothing, let packet pass through */
1129 } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
1130 info->flags |= IEEE80211_TX_CTL_AMPDU;
1131 } else {
1132 queued = true;
1133 info->control.vif = &tx->sdata->vif;
1134 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
1135 __skb_queue_tail(&tid_tx->pending, skb);
1136 }
1137 spin_unlock(&tx->sta->lock);
1138 }
1139
1140 return queued;
1141}
1142
1095/* 1143/*
1096 * initialises @tx 1144 * initialises @tx
1097 */ 1145 */
@@ -1104,8 +1152,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
1104 struct ieee80211_hdr *hdr; 1152 struct ieee80211_hdr *hdr;
1105 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1153 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1106 int hdrlen, tid; 1154 int hdrlen, tid;
1107 u8 *qc, *state; 1155 u8 *qc;
1108 bool queued = false;
1109 1156
1110 memset(tx, 0, sizeof(*tx)); 1157 memset(tx, 0, sizeof(*tx));
1111 tx->skb = skb; 1158 tx->skb = skb;
@@ -1157,35 +1204,16 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
1157 qc = ieee80211_get_qos_ctl(hdr); 1204 qc = ieee80211_get_qos_ctl(hdr);
1158 tid = *qc & IEEE80211_QOS_CTL_TID_MASK; 1205 tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
1159 1206
1160 spin_lock(&tx->sta->lock); 1207 tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
1161 /* 1208 if (tid_tx) {
1162 * XXX: This spinlock could be fairly expensive, but see the 1209 bool queued;
1163 * comment in agg-tx.c:ieee80211_agg_tx_operational().
1164 * One way to solve this would be to do something RCU-like
1165 * for managing the tid_tx struct and using atomic bitops
1166 * for the actual state -- by introducing an actual
1167 * 'operational' bit that would be possible. It would
1168 * require changing ieee80211_agg_tx_operational() to
1169 * set that bit, and changing the way tid_tx is managed
1170 * everywhere, including races between that bit and
1171 * tid_tx going away (tid_tx being added can be easily
1172 * committed to memory before the 'operational' bit).
1173 */
1174 tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
1175 state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
1176 if (*state == HT_AGG_STATE_OPERATIONAL) {
1177 info->flags |= IEEE80211_TX_CTL_AMPDU;
1178 } else if (*state != HT_AGG_STATE_IDLE) {
1179 /* in progress */
1180 queued = true;
1181 info->control.vif = &sdata->vif;
1182 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
1183 __skb_queue_tail(&tid_tx->pending, skb);
1184 }
1185 spin_unlock(&tx->sta->lock);
1186 1210
1187 if (unlikely(queued)) 1211 queued = ieee80211_tx_prep_agg(tx, skb, info,
1188 return TX_QUEUED; 1212 tid_tx, tid);
1213
1214 if (unlikely(queued))
1215 return TX_QUEUED;
1216 }
1189 } 1217 }
1190 1218
1191 if (is_multicast_ether_addr(hdr->addr1)) { 1219 if (is_multicast_ether_addr(hdr->addr1)) {