@@ -395,6 +395,67 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
395
395
return ret ;
396
396
}
397
397
398
+ static void iwl_mvm_release_frames (struct iwl_mvm * mvm ,
399
+ struct ieee80211_sta * sta ,
400
+ struct napi_struct * napi ,
401
+ struct iwl_mvm_reorder_buffer * reorder_buf ,
402
+ u16 nssn )
403
+ {
404
+ u16 ssn = reorder_buf -> head_sn ;
405
+
406
+ while (ieee80211_sn_less (ssn , nssn )) {
407
+ int index = ssn % reorder_buf -> buf_size ;
408
+ struct sk_buff_head * skb_list = & reorder_buf -> entries [index ];
409
+ struct sk_buff * skb ;
410
+
411
+ ssn = ieee80211_sn_inc (ssn );
412
+
413
+ /* holes are valid since nssn indicates frames were received. */
414
+ if (skb_queue_empty (skb_list ) || !skb_peek_tail (skb_list ))
415
+ continue ;
416
+ /* Empty the list. Will have more than one frame for A-MSDU */
417
+ while ((skb = __skb_dequeue (skb_list ))) {
418
+ iwl_mvm_pass_packet_to_mac80211 (mvm , napi , skb ,
419
+ reorder_buf -> queue ,
420
+ sta );
421
+ reorder_buf -> num_stored -- ;
422
+ }
423
+ }
424
+ reorder_buf -> head_sn = nssn ;
425
+ }
426
+
427
+ static void iwl_mvm_del_ba (struct iwl_mvm * mvm , int queue ,
428
+ struct iwl_mvm_delba_data * data )
429
+ {
430
+ struct iwl_mvm_baid_data * ba_data ;
431
+ struct ieee80211_sta * sta ;
432
+ struct iwl_mvm_reorder_buffer * reorder_buf ;
433
+ u8 baid = data -> baid ;
434
+
435
+ if (WARN_ON_ONCE (baid >= IWL_RX_REORDER_DATA_INVALID_BAID ))
436
+ return ;
437
+
438
+ rcu_read_lock ();
439
+
440
+ ba_data = rcu_dereference (mvm -> baid_map [baid ]);
441
+ if (WARN_ON_ONCE (!ba_data ))
442
+ goto out ;
443
+
444
+ sta = rcu_dereference (mvm -> fw_id_to_mac_id [ba_data -> sta_id ]);
445
+ if (WARN_ON_ONCE (IS_ERR_OR_NULL (sta )))
446
+ goto out ;
447
+
448
+ reorder_buf = & ba_data -> reorder_buf [queue ];
449
+
450
+ /* release all frames that are in the reorder buffer to the stack */
451
+ iwl_mvm_release_frames (mvm , sta , NULL , reorder_buf ,
452
+ ieee80211_sn_add (reorder_buf -> head_sn ,
453
+ reorder_buf -> buf_size ));
454
+
455
+ out :
456
+ rcu_read_unlock ();
457
+ }
458
+
398
459
void iwl_mvm_rx_queue_notif (struct iwl_mvm * mvm , struct iwl_rx_cmd_buffer * rxb ,
399
460
int queue )
400
461
{
@@ -418,12 +479,129 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
418
479
case IWL_MVM_RXQ_EMPTY :
419
480
break ;
420
481
case IWL_MVM_RXQ_NOTIF_DEL_BA :
482
+ iwl_mvm_del_ba (mvm , queue , (void * )internal_notif -> data );
421
483
break ;
422
484
default :
423
485
WARN_ONCE (1 , "Invalid identifier %d" , internal_notif -> type );
424
486
}
425
487
}
426
488
489
+ /*
490
+ * Returns true if the MPDU was buffered\dropped, false if it should be passed
491
+ * to upper layer.
492
+ */
493
+ static bool iwl_mvm_reorder (struct iwl_mvm * mvm ,
494
+ struct napi_struct * napi ,
495
+ int queue ,
496
+ struct ieee80211_sta * sta ,
497
+ struct sk_buff * skb ,
498
+ struct iwl_rx_mpdu_desc * desc )
499
+ {
500
+ struct ieee80211_hdr * hdr = (struct ieee80211_hdr * )skb -> data ;
501
+ struct iwl_mvm_sta * mvm_sta = iwl_mvm_sta_from_mac80211 (sta );
502
+ struct iwl_mvm_baid_data * baid_data ;
503
+ struct iwl_mvm_reorder_buffer * buffer ;
504
+ struct sk_buff * tail ;
505
+ u32 reorder = le32_to_cpu (desc -> reorder_data );
506
+ bool amsdu = desc -> mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU ;
507
+ u8 tid = * ieee80211_get_qos_ctl (hdr ) & IEEE80211_QOS_CTL_TID_MASK ;
508
+ u8 sub_frame_idx = desc -> amsdu_info &
509
+ IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK ;
510
+ int index ;
511
+ u16 nssn , sn ;
512
+ u8 baid ;
513
+
514
+ baid = (reorder & IWL_RX_MPDU_REORDER_BAID_MASK ) >>
515
+ IWL_RX_MPDU_REORDER_BAID_SHIFT ;
516
+
517
+ if (baid == IWL_RX_REORDER_DATA_INVALID_BAID )
518
+ return false;
519
+
520
+ /* no sta yet */
521
+ if (WARN_ON (IS_ERR_OR_NULL (sta )))
522
+ return false;
523
+
524
+ /* not a data packet */
525
+ if (!ieee80211_is_data_qos (hdr -> frame_control ) ||
526
+ is_multicast_ether_addr (hdr -> addr1 ))
527
+ return false;
528
+
529
+ if (unlikely (!ieee80211_is_data_present (hdr -> frame_control )))
530
+ return false;
531
+
532
+ baid_data = rcu_dereference (mvm -> baid_map [baid ]);
533
+ if (WARN (!baid_data ,
534
+ "Received baid %d, but no data exists for this BAID\n" , baid ))
535
+ return false;
536
+ if (WARN (tid != baid_data -> tid || mvm_sta -> sta_id != baid_data -> sta_id ,
537
+ "baid 0x%x is mapped to sta:%d tid:%d, but was received for sta:%d tid:%d\n" ,
538
+ baid , baid_data -> sta_id , baid_data -> tid , mvm_sta -> sta_id ,
539
+ tid ))
540
+ return false;
541
+
542
+ nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK ;
543
+ sn = (reorder & IWL_RX_MPDU_REORDER_SN_MASK ) >>
544
+ IWL_RX_MPDU_REORDER_SN_SHIFT ;
545
+
546
+ buffer = & baid_data -> reorder_buf [queue ];
547
+
548
+ /*
549
+ * If there was a significant jump in the nssn - adjust.
550
+ * If the SN is smaller than the NSSN it might need to first go into
551
+ * the reorder buffer, in which case we just release up to it and the
552
+ * rest of the function will take of storing it and releasing up to the
553
+ * nssn
554
+ */
555
+ if (!ieee80211_sn_less (nssn , buffer -> head_sn + buffer -> buf_size )) {
556
+ u16 min_sn = ieee80211_sn_less (sn , nssn ) ? sn : nssn ;
557
+
558
+ iwl_mvm_release_frames (mvm , sta , napi , buffer , min_sn );
559
+ }
560
+
561
+ /* drop any oudated packets */
562
+ if (ieee80211_sn_less (sn , buffer -> head_sn ))
563
+ goto drop ;
564
+
565
+ /* release immediately if allowed by nssn and no stored frames */
566
+ if (!buffer -> num_stored && ieee80211_sn_less (sn , nssn )) {
567
+ buffer -> head_sn = nssn ;
568
+ /* No need to update AMSDU last SN - we are moving the head */
569
+ return false;
570
+ }
571
+
572
+ index = sn % buffer -> buf_size ;
573
+
574
+ /*
575
+ * Check if we already stored this frame
576
+ * As AMSDU is either received or not as whole, logic is simple:
577
+ * If we have frames in that position in the buffer and the last frame
578
+ * originated from AMSDU had a different SN then it is a retransmission.
579
+ * If it is the same SN then if the subframe index is incrementing it
580
+ * is the same AMSDU - otherwise it is a retransmission.
581
+ */
582
+ tail = skb_peek_tail (& buffer -> entries [index ]);
583
+ if (tail && !amsdu )
584
+ goto drop ;
585
+ else if (tail && (sn != buffer -> last_amsdu ||
586
+ buffer -> last_sub_index >= sub_frame_idx ))
587
+ goto drop ;
588
+
589
+ /* put in reorder buffer */
590
+ __skb_queue_tail (& buffer -> entries [index ], skb );
591
+ buffer -> num_stored ++ ;
592
+ if (amsdu ) {
593
+ buffer -> last_amsdu = sn ;
594
+ buffer -> last_sub_index = sub_frame_idx ;
595
+ }
596
+
597
+ iwl_mvm_release_frames (mvm , sta , napi , buffer , nssn );
598
+ return true;
599
+
600
+ drop :
601
+ kfree_skb (skb );
602
+ return true;
603
+ }
604
+
427
605
static void iwl_mvm_agg_rx_received (struct iwl_mvm * mvm , u8 baid )
428
606
{
429
607
unsigned long now = jiffies ;
@@ -638,7 +816,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
638
816
/* TODO: PHY info - gscan */
639
817
640
818
iwl_mvm_create_skb (skb , hdr , len , crypt_len , rxb );
641
- iwl_mvm_pass_packet_to_mac80211 (mvm , napi , skb , queue , sta );
819
+ if (!iwl_mvm_reorder (mvm , napi , queue , sta , skb , desc ))
820
+ iwl_mvm_pass_packet_to_mac80211 (mvm , napi , skb , queue , sta );
642
821
rcu_read_unlock ();
643
822
}
644
823
0 commit comments