Commit e7e14089 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho

iwlwifi: mvm: do not trust NSSN for amsdu sub-frames

We cannot trust NSSN for AMSDU sub-frames that are not the
last.
The reason is that NSSN advances on the first sub-frame,
and may cause the reorder buffer to advance before all the
sub-frames arrive.
Example:
Reorder buffer contains SN 0 & 2.
We receive AMSDU with SN 1 and NSSN for first sub frame 3.
The result us that driver releases SN 0,1, 2.
When sub-frame 1 arrives - reorder buffer is already ahead and
it will be dropped.
If the last sub-frame is not on this queue - we will get frame
release notification with up to date NSSN.
Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 4bdd4dfe
...@@ -587,6 +587,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -587,6 +587,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
struct sk_buff *tail; struct sk_buff *tail;
u32 reorder = le32_to_cpu(desc->reorder_data); u32 reorder = le32_to_cpu(desc->reorder_data);
bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU; bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
bool last_subframe =
desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
u8 sub_frame_idx = desc->amsdu_info & u8 sub_frame_idx = desc->amsdu_info &
IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
...@@ -651,7 +653,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -651,7 +653,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
/* release immediately if allowed by nssn and no stored frames */ /* release immediately if allowed by nssn and no stored frames */
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
if (iwl_mvm_is_sn_less(buffer->head_sn, nssn, if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
buffer->buf_size)) buffer->buf_size) &&
(!amsdu || last_subframe))
buffer->head_sn = nssn; buffer->head_sn = nssn;
/* No need to update AMSDU last SN - we are moving the head */ /* No need to update AMSDU last SN - we are moving the head */
spin_unlock_bh(&buffer->lock); spin_unlock_bh(&buffer->lock);
...@@ -685,7 +688,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -685,7 +688,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
buffer->last_sub_index = sub_frame_idx; buffer->last_sub_index = sub_frame_idx;
} }
/*
* We cannot trust NSSN for AMSDU sub-frames that are not the last.
* The reason is that NSSN advances on the first sub-frame, and may
* cause the reorder buffer to advance before all the sub-frames arrive.
* Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
* SN 1. NSSN for first sub frame will be 3 with the result of driver
* releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
* already ahead and it will be dropped.
* If the last sub-frame is not on this queue - we will get frame
* release notification with up to date NSSN.
*/
if (!amsdu || last_subframe)
iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn); iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
spin_unlock_bh(&buffer->lock); spin_unlock_bh(&buffer->lock);
return true; return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment