return ret;
}
+/*
+ * Returns true if sn2 - buffer_size < sn1 < sn2.
+ * To be used only in order to compare reorder buffer head with NSSN.
+ * We fully trust NSSN unless it is behind us due to reorder timeout.
+ * Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN.
+ */
+static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size)
+{
+ return ieee80211_sn_less(sn1, sn2) &&
+ !ieee80211_sn_less(sn1, sn2 - buffer_size);
+}
+
#define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10)
static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
lockdep_assert_held(&reorder_buf->lock);
/* ignore nssn smaller than head sn - this can happen due to timeout */
- if (ieee80211_sn_less(nssn, ssn))
+ if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
return;
- while (ieee80211_sn_less(ssn, nssn)) {
+ while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) {
int index = ssn % reorder_buf->buf_size;
struct sk_buff_head *skb_list = &reorder_buf->entries[index];
struct sk_buff *skb;
* rest of the function will take of storing it and releasing up to the
* nssn
*/
- if (!ieee80211_sn_less(nssn, buffer->head_sn + buffer->buf_size)) {
+ if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size,
+ buffer->buf_size)) {
u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;
iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn);
/* release immediately if allowed by nssn and no stored frames */
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
- if (ieee80211_sn_less(buffer->head_sn, nssn))
+ if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
+ buffer->buf_size))
buffer->head_sn = nssn;
/* No need to update AMSDU last SN - we are moving the head */
spin_unlock_bh(&buffer->lock);