|
@@ -2312,6 +2312,15 @@ no_frame:
|
|
|
}
|
|
|
|
|
|
|
|
|
+/*
|
|
|
+ * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
|
|
|
+ * the skb was added to the buffer longer than this time ago, the earlier
|
|
|
+ * frames that have not yet been received are assumed to be lost and the skb
|
|
|
+ * can be released for processing. This may also release other skb's from the
|
|
|
+ * reorder buffer if there are no additional gaps between the frames.
|
|
|
+ */
|
|
|
+#define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
|
|
|
+
|
|
|
/*
|
|
|
* As it function blongs to Rx path it must be called with
|
|
|
* the proper rcu_read_lock protection for its flow.
|
|
@@ -2377,13 +2386,49 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* put the frame in the reordering buffer */
|
|
|
tid_agg_rx->reorder_buf[index] = skb;
|
|
|
+ tid_agg_rx->reorder_time[index] = jiffies;
|
|
|
memcpy(tid_agg_rx->reorder_buf[index]->cb, rxstatus,
|
|
|
sizeof(*rxstatus));
|
|
|
tid_agg_rx->stored_mpdu_num++;
|
|
|
/* release the buffer until next missing frame */
|
|
|
index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
|
|
|
% tid_agg_rx->buf_size;
|
|
|
- while (tid_agg_rx->reorder_buf[index]) {
|
|
|
+ if (!tid_agg_rx->reorder_buf[index] &&
|
|
|
+ tid_agg_rx->stored_mpdu_num > 1) {
|
|
|
+ /*
|
|
|
+ * No buffers ready to be released, but check whether any
|
|
|
+ * frames in the reorder buffer have timed out.
|
|
|
+ */
|
|
|
+ int j;
|
|
|
+ int skipped = 1;
|
|
|
+ for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
|
|
+ j = (j + 1) % tid_agg_rx->buf_size) {
|
|
|
+ if (tid_agg_rx->reorder_buf[j] == NULL) {
|
|
|
+ skipped++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
|
|
|
+ HZ / 10))
|
|
|
+ break;
|
|
|
+
|
|
|
+#ifdef CONFIG_MAC80211_HT_DEBUG
|
|
|
+ if (net_ratelimit())
|
|
|
+ printk(KERN_DEBUG "%s: release an RX reorder "
|
|
|
+ "frame due to timeout on earlier "
|
|
|
+ "frames\n",
|
|
|
+ wiphy_name(hw->wiphy));
|
|
|
+#endif
|
|
|
+ ieee80211_release_reorder_frame(hw, tid_agg_rx, j);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Increment the head seq# also for the skipped slots.
|
|
|
+ */
|
|
|
+ tid_agg_rx->head_seq_num =
|
|
|
+ (tid_agg_rx->head_seq_num + skipped) &
|
|
|
+ SEQ_MASK;
|
|
|
+ skipped = 0;
|
|
|
+ }
|
|
|
+ } else while (tid_agg_rx->reorder_buf[index]) {
|
|
|
ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
|
|
|
index = seq_sub(tid_agg_rx->head_seq_num,
|
|
|
tid_agg_rx->ssn) % tid_agg_rx->buf_size;
|