From a8295e2c06e1aa313b4624df9dedf599df382eef Mon Sep 17 00:00:00 2001
From: Ben Greear <greearb@candelatech.com>
Date: Thu, 9 May 2013 11:56:22 -0700
Subject: mac80211: Limit number of pending skbs.

Current code will allow any number of pending skbs, and
this can OOM the system when used with something like
the pktgen tool (which may not back off properly if
queue is stopped).

Possibly this is just a bug in our version of pktgen,
but either way, it seems reasonable to add a limit
so that it is not possible to go OOM in this manner.

Signed-off-by: Ben Greear <greearb@candelatech.com>

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3529d1368068..5eb60a50641e 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -35,6 +35,17 @@
 #include "wpa.h"
 #include "wme.h"
 #include "rate.h"
+#include <linux/moduleparam.h>
+
+/*
+ * Maximum number of skbs that may be queued in a pending
+ * queue.  After that, packets will just be dropped.
+ */
+static int max_pending_qsize = 1000;
+module_param(max_pending_qsize, int, 0644);
+MODULE_PARM_DESC(max_pending_qsize,
+		 "Maximum number of skbs that may be queued in a pending queue.");
+
 
 /* misc utils */
 
@@ -1671,15 +1682,28 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
 				 * later transmission from the tx-pending
 				 * tasklet when the queue is woken again.
 				 */
-				if (txpending)
+				bool do_free = false;
+				if (txpending) {
 					skb_queue_splice_init(skbs,
 							      &local->pending[q]);
-				else
-					skb_queue_splice_tail_init(skbs,
-								   &local->pending[q]);
+				} else {
+					u32 len = skb_queue_len(&local->pending[q]);
+					if (len >= max_pending_qsize) {
+						__skb_unlink(skb, skbs);
+						do_free = true;
+					} else {
+						skb_queue_splice_tail_init(skbs,
+									   &local->pending[q]);
+					}
+				}
 
 				spin_unlock_irqrestore(&local->queue_stop_reason_lock,
 						       flags);
+				if (do_free) {
+					dev_kfree_skb_any(skb);
+					/* TODO:  Add counter for this */
+				}
+
 				return false;
 			}
 		}
