@@ -395,6 +395,67 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
395395 return ret ;
396396}
397397
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+
398459void iwl_mvm_rx_queue_notif (struct iwl_mvm * mvm , struct iwl_rx_cmd_buffer * rxb ,
399460 int queue )
400461{
@@ -418,12 +479,129 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
418479 case IWL_MVM_RXQ_EMPTY :
419480 break ;
420481 case IWL_MVM_RXQ_NOTIF_DEL_BA :
482+ iwl_mvm_del_ba (mvm , queue , (void * )internal_notif -> data );
421483 break ;
422484 default :
423485 WARN_ONCE (1 , "Invalid identifier %d" , internal_notif -> type );
424486 }
425487}
426488
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+
427605static void iwl_mvm_agg_rx_received (struct iwl_mvm * mvm , u8 baid )
428606{
429607 unsigned long now = jiffies ;
@@ -638,7 +816,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
638816 /* TODO: PHY info - gscan */
639817
640818 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 );
642821 rcu_read_unlock ();
643822}
644823
0 commit comments