spin_lock_bh(&sta->lock);
/* free resources */
kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+ kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time);
if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
kfree(sta->ampdu_mlme.tid_rx[tid]);
/* prepare reordering buffer */
tid_agg_rx->reorder_buf =
kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
- if (!tid_agg_rx->reorder_buf) {
+ tid_agg_rx->reorder_time =
+ kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC);
+ if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "can not allocate reordering buffer "
"to tid %d\n", tid);
#endif
+ kfree(tid_agg_rx->reorder_buf);
+ kfree(tid_agg_rx->reorder_time);
kfree(sta->ampdu_mlme.tid_rx[tid]);
+ sta->ampdu_mlme.tid_rx[tid] = NULL;
goto end;
}
}
+/*
+ * 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.
/* 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;
* struct tid_ampdu_rx - TID aggregation information (Rx).
*
* @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @reorder_time: jiffies when skb was added
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
* @head_seq_num: head sequence number in reordering buffer.
* @stored_mpdu_num: number of MPDUs in reordering buffer
*/
struct tid_ampdu_rx {
struct sk_buff **reorder_buf;
+ unsigned long *reorder_time;
struct timer_list session_timer;
u16 head_seq_num;
u16 stored_mpdu_num;