From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Fri, 18 Jul 2008 22:57:30 +0000 (+0000)
Subject: rename patches-r3776 to patches-testing
X-Git-Url: https://git.rohieb.name/openwrt.git/commitdiff_plain/04ce7928c6f6f644f5619e6617bf0aa86826abf9

rename patches-r3776 to patches-testing


git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11868 3c298f89-4303-0410-b956-a3cf2f4a3e73
---

diff --git a/package/madwifi/Makefile b/package/madwifi/Makefile
index 0711e6d57..48fa28e12 100644
--- a/package/madwifi/Makefile
+++ b/package/madwifi/Makefile
@@ -23,7 +23,7 @@ PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
 
 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(if $(PKG_BRANCH),$(PKG_BRANCH),madwifi-trunk)-$(PKG_VERSION)
 
-PATCH_DIR=$(if $(CONFIG_MADWIFI_TESTING),./patches-r$(PKG_REV),./patches)
+PATCH_DIR=$(if $(CONFIG_MADWIFI_TESTING),./patches-testing,./patches)
 
 include $(INCLUDE_DIR)/package.mk
 
diff --git a/package/madwifi/patches-r3776/102-multicall_binary.patch b/package/madwifi/patches-r3776/102-multicall_binary.patch
deleted file mode 100644
index 7ddd45632..000000000
--- a/package/madwifi/patches-r3776/102-multicall_binary.patch
+++ /dev/null
@@ -1,359 +0,0 @@
---- a/tools/80211debug.c
-+++ b/tools/80211debug.c
-@@ -48,6 +48,7 @@
- #include <ctype.h>
- #include <getopt.h>
- #include <err.h>
-+#include "do_multi.h"
- 
- #undef ARRAY_SIZE
- #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-@@ -185,7 +186,7 @@
- #endif /* __linux__ */
- 
- int
--main(int argc, char *argv[])
-+CMD(a80211debug)(int argc, char *argv[])
- {
- 	const char *ifname = "ath0";
- 	const char *cp, *tp;
---- a/tools/80211stats.c
-+++ b/tools/80211stats.c
-@@ -59,6 +59,7 @@
- #include "net80211/ieee80211.h"
- #include "net80211/ieee80211_crypto.h"
- #include "net80211/ieee80211_ioctl.h"
-+#include "do_multi.h"
- 
- #ifndef SIOCG80211STATS
- #define	SIOCG80211STATS	(SIOCDEVPRIVATE + 2)
-@@ -241,7 +242,7 @@
- }
- 
- int
--main(int argc, char *argv[])
-+CMD(a80211stats)(int argc, char *argv[])
- {
- 	int c, len;
- 	struct ieee80211req_sta_info *si;
---- a/tools/athchans.c
-+++ b/tools/athchans.c
-@@ -58,6 +58,7 @@
- #include "net80211/ieee80211.h"
- #include "net80211/ieee80211_crypto.h"
- #include "net80211/ieee80211_ioctl.h"
-+#include "do_multi.h"
- 
- static	int s = -1;
- static const char *progname;
-@@ -140,8 +141,9 @@
- }
- 
- #define	MAXCHAN	((int)(sizeof(struct ieee80211req_chanlist) * NBBY))
-+
- int
--main(int argc, char *argv[])
-+CMD(athchans)(int argc, char *argv[])
- {
- 	const char *ifname = "wifi0";
- 	struct ieee80211req_chanlist chanlist;
---- a/tools/athctrl.c
-+++ b/tools/athctrl.c
-@@ -52,6 +52,7 @@
- #include <err.h>
- 
- #include <net/if.h>
-+#include "do_multi.h"
- 
- static int
- setsysctrl(const char *dev, const char *control , u_long value)
-@@ -88,7 +89,7 @@
- }
- 
- int
--main(int argc, char *argv[])
-+CMD(athctrl)(int argc, char *argv[])
- {
- 	char device[IFNAMSIZ + 1];
- 	int distance = -1;
---- a/tools/athdebug.c
-+++ b/tools/athdebug.c
-@@ -51,6 +51,7 @@
- #include <ctype.h>
- #include <getopt.h>
- #include <err.h>
-+#include "do_multi.h"
- 
- #undef ARRAY_SIZE
- #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-@@ -194,7 +195,7 @@
- #endif /* __linux__ */
- 
- int
--main(int argc, char *argv[])
-+CMD(athdebug)(int argc, char *argv[])
- {
- #ifdef __linux__
- 	const char *ifname = "wifi0";
---- a/tools/athkey.c
-+++ b/tools/athkey.c
-@@ -58,6 +58,7 @@
- #include "net80211/ieee80211.h"
- #include "net80211/ieee80211_crypto.h"
- #include "net80211/ieee80211_ioctl.h"
-+#include "do_multi.h"
- 
- static int s = -1;
- static const char *progname;
-@@ -213,8 +214,7 @@
- 	exit(-1);
- }
- 
--int
--main(int argc, char *argv[])
-+int CMD(athkey)(int argc, char *argv[])
- {
- 	const char *ifname = "wifi0";
- 	struct ieee80211req_key setkey;
---- a/tools/athstats.c
-+++ b/tools/athstats.c
-@@ -65,6 +65,7 @@
- 
- #undef ARRAY_SIZE
- #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-+#include "do_multi.h"
- 
- static const struct {
- 	u_int		phyerr;
-@@ -228,7 +229,7 @@
- }
- 
- int
--main(int argc, char *argv[])
-+CMD(athstats)(int argc, char *argv[])
- {
- #ifdef __linux__
- 	const char *ifname = "wifi0";
---- /dev/null
-+++ b/tools/do_multi.c
-@@ -0,0 +1,36 @@
-+#include <string.h>
-+#include "do_multi.h"
-+
-+int
-+main(int argc, char *argv[])
-+{
-+    char *progname;
-+    int ret = 0;
-+
-+    progname = basename(argv[0]);
-+
-+    if(strcmp(progname, "80211debug") == 0)
-+	ret = a80211debug_init(argc, argv);
-+    if(strcmp(progname, "80211stats") == 0)
-+	ret = a80211stats_init(argc, argv);
-+    if(strcmp(progname, "athchans") == 0)
-+	ret = athchans_init(argc, argv);
-+    if(strcmp(progname, "athctrl") == 0)
-+	ret =  athctrl_init(argc, argv);
-+    if(strcmp(progname, "athdebug") == 0)
-+	ret =  athdebug_init(argc, argv);
-+    if(strcmp(progname, "athkey") == 0)
-+	ret =  athkey_init(argc, argv);
-+    if(strcmp(progname, "athstats") == 0)
-+	ret =  athstats_init(argc, argv);
-+    if(strcmp(progname, "wlanconfig") == 0)
-+	ret =  wlanconfig_init(argc, argv);
-+    if(strcmp(progname, "wpakey") == 0)
-+	ret =  wpakey_init(argc, argv);
-+    if(strcmp(progname, "athchans") == 0)
-+	ret =  athchans_init(argc, argv);
-+    if(strcmp(progname, "ath_info") == 0)
-+	ret =  athinfo_init(argc, argv);
-+
-+    return ret;
-+}
---- /dev/null
-+++ b/tools/do_multi.h
-@@ -0,0 +1,15 @@
-+#ifdef DO_MULTI
-+int a80211debug_init(int argc, char *argv[]);
-+int a80211stats_init(int argc, char *argv[]);
-+int athchans_init(int argc, char *argv[]);
-+int athctrl_init(int argc, char *argv[]);
-+int athdebug_init(int argc, char *argv[]);
-+int athkey_init(int argc, char *argv[]);
-+int athstats_init(int argc, char *argv[]);
-+int wlanconfig_init(int argc, char *argv[]);
-+int athinfo_init(int argc, char *argv[]);
-+
-+#define CMD(name) name##_init
-+#else
-+#define CMD(name) main
-+#endif
---- a/tools/Makefile
-+++ b/tools/Makefile
-@@ -50,42 +50,43 @@
- PROGRAMS = athstats 80211stats athkey athchans athctrl \
- 	athdebug 80211debug wlanconfig wpakey
- 
-+OBJS = $(patsubst %,%.o,$(PROGRAMS)) ath_info/ath_info.o
- SUBDIRS = ath_info
- 
--INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL)
-+INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
- CFLAGS = -g -O2 -Wall
- ALL_CFLAGS = $(CFLAGS) $(INCS)
- LDFLAGS =
- 
--all: all-subdirs $(PROGRAMS)
-+all: all-subdirs compile
- 
- all-subdirs:
- 	for d in $(SUBDIRS); do \
- 		$(MAKE) -C $$d || exit 1; \
- 	done
- 
--athstats: athstats.c
--	$(CC) -o athstats $(ALL_CFLAGS) -I$(TOP)/ath $(LDFLAGS) athstats.c
--80211stats: 80211stats.c
--	$(CC) -o 80211stats $(ALL_CFLAGS) $(LDFLAGS) 80211stats.c
--athkey: athkey.c
--	$(CC) -o athkey $(ALL_CFLAGS) $(LDFLAGS) athkey.c
--athchans: athchans.c
--	$(CC) -o athchans $(ALL_CFLAGS) $(LDFLAGS) athchans.c
--athctrl: athctrl.c
--	$(CC) -o athctrl $(ALL_CFLAGS) $(LDFLAGS) athctrl.c
--athdebug: athdebug.c
--	$(CC) -o athdebug $(ALL_CFLAGS) $(LDFLAGS) athdebug.c
--wlanconfig: wlanconfig.c
--	$(CC) -o wlanconfig $(ALL_CFLAGS) $(LDFLAGS) wlanconfig.c
--80211debug: 80211debug.c
--	$(CC) -o 80211debug $(ALL_CFLAGS) $(LDFLAGS) 80211debug.c
--wpakey: wpakey.c
--	$(CC) -o wpakey $(ALL_CFLAGS) $(LDFLAGS) wpakey.c
-+%.o: %.c
-+	${CC} $(ALL_CFLAGS) -c -o $@  $<
-+
-+ifneq ($(DO_MULTI),)
-+ALL_CFLAGS += -DDO_MULTI=1
-+madwifi_multi: $(OBJS) do_multi.o
-+	$(CC) $(LDFLAGS) -o $@ $^
-+
-+compile: madwifi_multi
-+	for i in $(PROGRAMS); do \
-+		ln -sf madwifi_multi $$i; \
-+	done
-+else
-+$(PROGRAMS):
-+	$(CC) $(ALL_CFLAGS) -o $@ $@.c
-+
-+compile: $(PROGRAMS)
-+endif
- 
- install: all
- 	install -d $(DESTDIR)$(BINDIR)
--	for i in $(PROGRAMS); do \
-+	for i in $(PROGRAMS) $(if $(DO_MULTI),madwifi_multi); do \
- 		install $$i $(DESTDIR)$(BINDIR)/$$i; \
- 		$(STRIP) $(DESTDIR)$(BINDIR)/$$i; \
- 	done
-@@ -97,7 +98,7 @@
- 	done
- 
- uninstall:
--	for i in $(PROGRAMS); do \
-+	for i in $(PROGRAMS) $(if $(DO_MULTI),madwifi_multi); do \
- 		rm -f $(DESTDIR)$(BINDIR)/$$i; \
- 	done
- 	for i in $(PROGRAMS:=.8); do \
-@@ -108,7 +109,7 @@
- 	done
- 
- clean:
--	rm -f $(PROGRAMS) core a.out
-+	rm -f $(if $(DO_MULTI), madwifi_multi) $(PROGRAMS) core a.out *.o
- 	for d in $(SUBDIRS); do \
- 		$(MAKE) -C $$d clean; \
- 	done
---- a/tools/wlanconfig.c
-+++ b/tools/wlanconfig.c
-@@ -61,6 +61,7 @@
- #include "net80211/ieee80211.h"
- #include "net80211/ieee80211_crypto.h"
- #include "net80211/ieee80211_ioctl.h"
-+#include "do_multi.h"
- 
- /*
-  * These are taken from ieee80211_node.h
-@@ -100,7 +101,7 @@
- static int verbose = 0;
- 
- int
--main(int argc, char *argv[])
-+CMD(wlanconfig)(int argc, char *argv[])
- {
- 	const char *ifname, *cmd;
- 	unsigned char bnounit = 0;
---- a/tools/ath_info/Makefile
-+++ b/tools/ath_info/Makefile
-@@ -17,11 +17,18 @@
- 
- all: $(PROGRAMS)
- 
-+
-+ifneq ($(DO_MULTI),)
-+ath_info: ath_info.o
-+	rm -f $@
-+	ln -s ../madwifi_multi $@
-+else
- ath_info: ath_info.o
- 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
-+endif
- 
- .c.o:
--	$(CC) $(CFLAGS) -c $<
-+	$(CC) $(CFLAGS) $(if $(DO_MULTI),-DDO_MULTI=1 -I..) -c $<
- 
- clean:
- 	rm -f *.o $(PROGRAMS)
---- a/tools/ath_info/ath_info.c
-+++ b/tools/ath_info/ath_info.c
-@@ -28,6 +28,7 @@
- #include <sys/mman.h>
- #include <endian.h>
- #include <byteswap.h>
-+#include "do_multi.h"
- 
- #undef ARRAY_SIZE
- #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-@@ -1982,7 +1983,8 @@
- 	printf("\n");
- }
- 
--int main(int argc, char *argv[])
-+int
-+CMD(athinfo)(int argc, char *argv[])
- {
- 	unsigned long long dev_addr;
- 	u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic;
---- a/tools/wpakey.c
-+++ b/tools/wpakey.c
-@@ -25,6 +25,7 @@
- 
- #include <unistd.h>
- #include <sys/ioctl.h>
-+#include "do_multi.h"
- 
- #define MACS "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
- #define MACP(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3], (mac)[4], (mac)[5]
-@@ -234,7 +235,8 @@
- 		"", dev);
- }
- 
--int main(int argc, char** argv) {
-+int
-+CMD(wpakey)(int argc, char** argv) {
- 	int keyidx = 0;
- 	uint8_t mac[6];
- 	int cipher = IEEE80211_CIPHER_AES_CCM;
diff --git a/package/madwifi/patches-r3776/104-autocreate_none.patch b/package/madwifi/patches-r3776/104-autocreate_none.patch
deleted file mode 100644
index 16ce6e863..000000000
--- a/package/madwifi/patches-r3776/104-autocreate_none.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -482,7 +482,7 @@
- 	HAL_STATUS status;
- 	int error = 0;
- 	unsigned int i;
--	int autocreatemode = IEEE80211_M_STA;
-+	int autocreatemode = -1;
- 	u_int8_t csz;
- 
- 	sc->devid = devid;
diff --git a/package/madwifi/patches-r3776/105-ratectl_attach.patch b/package/madwifi/patches-r3776/105-ratectl_attach.patch
deleted file mode 100644
index 79b08dfb8..000000000
--- a/package/madwifi/patches-r3776/105-ratectl_attach.patch
+++ /dev/null
@@ -1,23 +0,0 @@
---- a/net80211/ieee80211_rate.c
-+++ b/net80211/ieee80211_rate.c
-@@ -100,8 +100,18 @@
- 		ieee80211_load_module(buf);
- 
- 	if (!ratectls[id].attach) {
--		printk(KERN_ERR "Error loading module \"%s\"\n", buf);
--		return NULL;
-+		/* pick the first available rate control module */
-+		printk(KERN_INFO "Rate control module \"%s\" not available\n", buf);
-+		for (id = 0; id < IEEE80211_RATE_MAX; id++) {
-+			if (ratectls[id].attach)
-+				break;
-+		}
-+		if (!ratectls[id].attach) {
-+			printk(KERN_ERR "No rate control module available");
-+			return NULL;
-+		} else {
-+			printk(KERN_INFO "Using \"%s\" instead.\n", module_names[id]);
-+		}
- 	}
- 
- 	ctl = ratectls[id].attach(sc);
diff --git a/package/madwifi/patches-r3776/111-minstrel_crash.patch b/package/madwifi/patches-r3776/111-minstrel_crash.patch
deleted file mode 100644
index dd96c4e60..000000000
--- a/package/madwifi/patches-r3776/111-minstrel_crash.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- a/ath_rate/minstrel/minstrel.c
-+++ b/ath_rate/minstrel/minstrel.c
-@@ -415,6 +415,9 @@
- 			return;
- 		}
- 
-+		if (sn->num_rates <= 0)
-+			return;
-+
- 		if (sn->is_sampling) {
- 			sn->is_sampling = 0;
- 			if (sn->rs_sample_rate_slower)
diff --git a/package/madwifi/patches-r3776/122-replayfail_workaround.patch b/package/madwifi/patches-r3776/122-replayfail_workaround.patch
deleted file mode 100644
index de5a8f316..000000000
--- a/package/madwifi/patches-r3776/122-replayfail_workaround.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- a/net80211/ieee80211_linux.c
-+++ b/net80211/ieee80211_linux.c
-@@ -330,6 +330,9 @@
- 		k->wk_cipher->ic_name, k->wk_keyix,
- 		(unsigned long long)rsc);
- 
-+	/* disabled for now due to bogus events for unknown reasons */
-+	return;
-+
- 	/* TODO: needed parameters: count, keyid, key type, src address, TSC */
- 	snprintf(buf, sizeof(buf), "%s(keyid=%d %scast addr=" MAC_FMT ")", tag,
- 		k->wk_keyix,
diff --git a/package/madwifi/patches-r3776/123-ccmp_checks.patch b/package/madwifi/patches-r3776/123-ccmp_checks.patch
deleted file mode 100644
index 6db9c2d78..000000000
--- a/package/madwifi/patches-r3776/123-ccmp_checks.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/net80211/ieee80211_crypto_ccmp.c
-+++ b/net80211/ieee80211_crypto_ccmp.c
-@@ -478,6 +478,9 @@
- 	uint8_t *mic, *pos;
- 	u_int space;
- 
-+	if (ctx->cc_tfm == NULL)
-+		return 0;
-+
- 	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
- 
- 	skb = skb0;
-@@ -592,6 +595,9 @@
- 	uint8_t *pos, *mic;
- 	u_int space;
- 
-+	if (ctx->cc_tfm == NULL)
-+		return 0;
-+
- 	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
- 
- 	skb = skb0;
diff --git a/package/madwifi/patches-r3776/124-linux24_compat.patch b/package/madwifi/patches-r3776/124-linux24_compat.patch
deleted file mode 100644
index 2ab9364b9..000000000
--- a/package/madwifi/patches-r3776/124-linux24_compat.patch
+++ /dev/null
@@ -1,202 +0,0 @@
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -129,6 +129,11 @@
- #define ATH_GET_NETDEV_DEV(ndev)	((ndev)->class_dev.dev)
- #endif
- 
-+#ifndef NETDEV_TX_OK
-+#define NETDEV_TX_OK    0
-+#define NETDEV_TX_BUSY  1
-+#endif
-+
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
- static inline struct net_device *_alloc_netdev(int sizeof_priv, const char *mask,
- 					       void (*setup)(struct net_device *))
---- a/ath/if_ath_radar.c
-+++ b/ath/if_ath_radar.c
-@@ -89,6 +89,13 @@
- #define nofloat_pct(_value, _pct) \
- 	( (_value * (1000 + _pct)) / 1000 )
- 
-+#ifndef list_for_each_entry_reverse
-+#define list_for_each_entry_reverse(pos, head, member)			\
-+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
-+	     prefetch(pos->member.prev), &pos->member != (head); 	\
-+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
-+#endif
-+
- struct radar_pattern_specification {
- 	/* The name of the rule/specification (i.e. what did we detect) */
- 	const char *name;
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -4878,6 +4878,46 @@
- 	return (txqs & (1 << qnum));
- }
- 
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
-+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-+{
-+	int ret;
-+	unsigned long flags;
-+
-+	local_irq_save(flags);
-+	ret = v->counter;
-+	if (likely(ret == old))
-+		v->counter = new;
-+	local_irq_restore(flags);
-+
-+	return ret;
-+}
-+
-+/**
-+ * atomic_add_unless - add unless the number is a given value
-+ * @v: pointer of type atomic_t
-+ * @a: the amount to add to v...
-+ * @u: ...unless v is equal to u.
-+ *
-+ * Atomically adds @a to @v, so long as it was not @u.
-+ * Returns non-zero if @v was not @u, and zero otherwise.
-+ */
-+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
-+{
-+	int c, old;
-+	c = atomic_read(v);
-+	for (;;) {
-+		if (unlikely(c == (u)))
-+			break;
-+		old = atomic_cmpxchg((v), c, c + (a));
-+		if (likely(old == c))
-+			break;
-+		c = old;
-+	}
-+	return c != (u);
-+}
-+#endif
-+
- /*
-  * Generate beacon frame and queue cab data for a VAP.
-  */
---- /dev/null
-+++ b/net80211/sort.c
-@@ -0,0 +1,120 @@
-+/*
-+ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
-+ *
-+ * Jan 23 2005  Matt Mackall <mpm@selenic.com>
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+
-+static void u32_swap(void *a, void *b, int size)
-+{
-+	u32 t = *(u32 *)a;
-+	*(u32 *)a = *(u32 *)b;
-+	*(u32 *)b = t;
-+}
-+
-+static void generic_swap(void *a, void *b, int size)
-+{
-+	char t;
-+
-+	do {
-+		t = *(char *)a;
-+		*(char *)a++ = *(char *)b;
-+		*(char *)b++ = t;
-+	} while (--size > 0);
-+}
-+
-+/**
-+ * sort - sort an array of elements
-+ * @base: pointer to data to sort
-+ * @num: number of elements
-+ * @size: size of each element
-+ * @cmp: pointer to comparison function
-+ * @swap: pointer to swap function or NULL
-+ *
-+ * This function does a heapsort on the given array. You may provide a
-+ * swap function optimized to your element type.
-+ *
-+ * Sorting time is O(n log n) both on average and worst-case. While
-+ * qsort is about 20% faster on average, it suffers from exploitable
-+ * O(n*n) worst-case behavior and extra memory requirements that make
-+ * it less suitable for kernel use.
-+ */
-+
-+static void sort(void *base, size_t num, size_t size,
-+	  int (*cmp)(const void *, const void *),
-+	  void (*swap)(void *, void *, int size))
-+{
-+	/* pre-scale counters for performance */
-+	int i = (num/2 - 1) * size, n = num * size, c, r;
-+
-+	if (!swap)
-+		swap = (size == 4 ? u32_swap : generic_swap);
-+
-+	/* heapify */
-+	for ( ; i >= 0; i -= size) {
-+		for (r = i; r * 2 + size < n; r  = c) {
-+			c = r * 2 + size;
-+			if (c < n - size && cmp(base + c, base + c + size) < 0)
-+				c += size;
-+			if (cmp(base + r, base + c) >= 0)
-+				break;
-+			swap(base + r, base + c, size);
-+		}
-+	}
-+
-+	/* sort */
-+	for (i = n - size; i >= 0; i -= size) {
-+		swap(base, base + i, size);
-+		for (r = 0; r * 2 + size < i; r = c) {
-+			c = r * 2 + size;
-+			if (c < i - size && cmp(base + c, base + c + size) < 0)
-+				c += size;
-+			if (cmp(base + r, base + c) >= 0)
-+				break;
-+			swap(base + r, base + c, size);
-+		}
-+	}
-+}
-+
-+EXPORT_SYMBOL(sort);
-+
-+#if 0
-+/* a simple boot-time regression test */
-+
-+int cmpint(const void *a, const void *b)
-+{
-+	return *(int *)a - *(int *)b;
-+}
-+
-+static int sort_test(void)
-+{
-+	int *a, i, r = 1;
-+
-+	a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
-+	BUG_ON(!a);
-+
-+	printk("testing sort()\n");
-+
-+	for (i = 0; i < 1000; i++) {
-+		r = (r * 725861) % 6599;
-+		a[i] = r;
-+	}
-+
-+	sort(a, 1000, sizeof(int), cmpint, NULL);
-+
-+	for (i = 0; i < 999; i++)
-+		if (a[i] > a[i+1]) {
-+			printk("sort() failed!\n");
-+			break;
-+		}
-+
-+	kfree(a);
-+
-+	return 0;
-+}
-+
-+module_init(sort_test);
-+#endif
diff --git a/package/madwifi/patches-r3776/126-rxerr_frames.patch b/package/madwifi/patches-r3776/126-rxerr_frames.patch
deleted file mode 100644
index f95124135..000000000
--- a/package/madwifi/patches-r3776/126-rxerr_frames.patch
+++ /dev/null
@@ -1,27 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -6451,9 +6451,6 @@
- 		rs = &bf->bf_dsstatus.ds_rxstat;
- 
- 		len = rs->rs_datalen;
--		/* DMA sync. dies spectacularly if len == 0 */
--		if (len == 0)
--			goto rx_next;
- 		if (rs->rs_more) {
- 			/* Frame spans multiple descriptors; this
- 			 * cannot happen yet as we don't support
-@@ -6513,8 +6510,12 @@
- 		 * setup again to receive another frame. 
- 		 * NB: Meta-data (rs, noise, tsf) in the ath_buf is still
- 		 * used. */
--		bus_dma_sync_single(sc->sc_bdev,
--			bf->bf_skbaddr, len, BUS_DMA_FROMDEVICE);
-+
-+		/* DMA sync. dies spectacularly if len == 0 */
-+		if (len != 0) {
-+			bus_dma_sync_single(sc->sc_bdev,
-+				bf->bf_skbaddr, len, BUS_DMA_FROMDEVICE);
-+		}
- 		skb = ath_rxbuf_take_skb(sc, bf);
- 
- 		sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
diff --git a/package/madwifi/patches-r3776/200-no_debug.patch b/package/madwifi/patches-r3776/200-no_debug.patch
deleted file mode 100644
index 0797f8fb6..000000000
--- a/package/madwifi/patches-r3776/200-no_debug.patch
+++ /dev/null
@@ -1,420 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -323,8 +323,10 @@
- static void ath_set_dfs_cac_time(struct ieee80211com *, unsigned int seconds);
- 
- static unsigned int ath_test_radar(struct ieee80211com *);
--static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
-+#ifdef AR_DEBUG
- 
-+static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
-+#endif
- static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc);
- static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
- 		u_int32_t new_clamped_maxtxpower);
-@@ -334,7 +336,10 @@
- 		unsigned int param, unsigned int value);
- 
- static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
-+
-+#ifdef AR_DEBUG
- static int ath_txq_check(struct ath_softc *sc, struct ath_txq *txq, const char *msg);
-+#endif
- 
- static int ath_countrycode = CTRY_DEFAULT;	/* country code */
- static int ath_outdoor = AH_FALSE;		/* enable outdoor use */
-@@ -486,9 +491,11 @@
- 	u_int8_t csz;
- 
- 	sc->devid = devid;
-+#ifdef AR_DEBUG
- 	ath_debug_global = (ath_debug & ATH_DEBUG_GLOBAL);
- 	sc->sc_debug 	 = (ath_debug & ~ATH_DEBUG_GLOBAL);
- 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
-+#endif
- 
- 	/* Allocate space for dynamically determined maximum VAP count */
- 	sc->sc_bslot = 
-@@ -1014,7 +1021,9 @@
- 	ic->ic_vap_delete = ath_vap_delete;
- 
- 	ic->ic_test_radar		= ath_test_radar;
-+#ifdef AR_DEBUG
- 	ic->ic_dump_hal_map		= ath_dump_hal_map;
-+#endif
- 
- 	ic->ic_set_dfs_testmode		= ath_set_dfs_testmode;
- 	ic->ic_get_dfs_testmode		= ath_get_dfs_testmode;
-@@ -1285,12 +1294,14 @@
- 		/* If no default VAP debug flags are passed, allow a few to
- 		 * transfer down from the driver to new VAPs so we can have load
- 		 * time debugging for VAPs too. */
-+#ifdef AR_DEBUG
- 		vap->iv_debug = 0 |
- 			((sc->sc_debug & ATH_DEBUG_RATE) ? IEEE80211_MSG_XRATE  : 0) | 
- 			((sc->sc_debug & ATH_DEBUG_XMIT) ? IEEE80211_MSG_OUTPUT : 0) | 
- 			((sc->sc_debug & ATH_DEBUG_RECV) ? IEEE80211_MSG_INPUT  : 0) |
- 			0
- 			;
-+#endif
- 	}
- 	ic->ic_debug = (sc->sc_default_ieee80211_debug & IEEE80211_MSG_IC);
- 
-@@ -2811,6 +2822,7 @@
- #endif
- }
- 
-+#ifdef AR_DEBUG
- static void
- ath_txq_dump(struct ath_softc *sc, struct ath_txq *txq)
- {
-@@ -2866,6 +2878,7 @@
- 
- 	return 1;
- }
-+#endif
- 
- /*
-  * Insert a buffer on a txq
-@@ -8384,7 +8397,9 @@
- ath_tx_timeout(struct net_device *dev)
- {
- 	struct ath_softc *sc = dev->priv;
-+#ifdef AR_DEBUG
- 	int i;
-+#endif
- 
- 	if (ath_chan_unavail(sc))
- 		return;
-@@ -8393,12 +8408,14 @@
- 		(dev->flags & IFF_RUNNING) ? "" : "NOT ",
- 		sc->sc_invalid ? "in" : "");
- 
-+#ifdef AR_DEBUG
- 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
- 		if (ATH_TXQ_SETUP(sc, i)) {
- 			ath_txq_check(sc, &sc->sc_txq[i], __func__);
- 			ath_txq_dump(sc, &sc->sc_txq[i]);
- 		}
- 	}
-+#endif
- 
- 	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
- 		sc->sc_stats.ast_watchdog++;
-@@ -10638,6 +10655,7 @@
- 				/* XXX validate? */
- 				sc->sc_ledpin = val;
- 				break;
-+#ifdef AR_DEBUG
- 			case ATH_DEBUG:
- 				sc->sc_debug 	 = (val & ~ATH_DEBUG_GLOBAL);
- 				ath_debug_global = (val &  ATH_DEBUG_GLOBAL);
-@@ -10645,6 +10663,7 @@
- 						"0x%08x.\n", val);
- 
- 				break;
-+#endif
- 			case ATH_TXANTENNA:
- 				/*
- 				 * antenna can be:
-@@ -10818,9 +10837,11 @@
- 		case ATH_REGDOMAIN:
- 			ath_hal_getregdomain(ah, &val);
- 			break;
-+#ifdef AR_DEBUG
- 		case ATH_DEBUG:
- 			val = sc->sc_debug | ath_debug_global;
- 			break;
-+#endif
- 		case ATH_TXANTENNA:
- 			val = sc->sc_txantenna;
- 			break;
-@@ -11939,6 +11960,7 @@
- }
- 
- /* This is called by a private ioctl (iwpriv) to dump the HAL obfuscation table */
-+#ifdef AR_DEBUG
- static unsigned int
- ath_dump_hal_map(struct ieee80211com *ic)
- {
-@@ -11947,7 +11969,7 @@
- 	ath_hal_dump_map(sc->sc_ah);
- 	return 0;
- }
--
-+#endif
- /* If we are shutting down or blowing off the DFS channel availability check
-  * then we call this to stop the behavior before we take the rest of the
-  * necessary actions (such as a DFS reaction to radar). */
---- a/ath_rate/amrr/amrr.c
-+++ b/ath_rate/amrr/amrr.c
-@@ -70,7 +70,9 @@
- 
- #include "amrr.h"
- 
-+#ifdef AR_DEBUG
- #define	AMRR_DEBUG
-+#endif
- #ifdef AMRR_DEBUG
- #define	DPRINTF(sc, _fmt, ...) do {					\
- 	if (sc->sc_debug & 0x10)					\
---- a/ath_rate/minstrel/minstrel.c
-+++ b/ath_rate/minstrel/minstrel.c
-@@ -117,7 +117,9 @@
- 
- #include "minstrel.h"
- 
-+#ifdef AR_DEBUG
- #define	MINSTREL_DEBUG
-+#endif
- #ifdef MINSTREL_DEBUG
- enum {
- 		ATH_DEBUG_RATE		= 0x00000010	/* rate control */
-@@ -963,7 +965,9 @@
- 		(struct ieee80211_node_table *)&vap->iv_ic->ic_sta;
- 	unsigned int x = 0;
- 	unsigned int this_tp, this_prob, this_eprob;
--	struct ath_softc *sc = vap->iv_ic->ic_dev->priv;;
-+#ifdef AR_DEBUG
-+	struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
-+#endif
- 
- 	IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
- 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
---- a/ath_rate/onoe/onoe.c
-+++ b/ath_rate/onoe/onoe.c
-@@ -66,7 +66,9 @@
- 
- #include "onoe.h"
- 
-+#ifdef AR_DEBUG
- #define	ONOE_DEBUG
-+#endif
- #ifdef ONOE_DEBUG
- enum {
- 	ATH_DEBUG_RATE	= 0x00000010,	/* rate control */
---- a/ath_rate/sample/sample.c
-+++ b/ath_rate/sample/sample.c
-@@ -68,7 +68,9 @@
- 
- #include "sample.h"
- 
--#define	SAMPLE_DEBUG
-+#ifdef AR_DEBUG
-+#define SAMPLE_DEBUG
-+#endif
- #ifdef SAMPLE_DEBUG
- enum {
- 	ATH_DEBUG_RATE		= 0x00000010,	/* rate control */
---- a/tools/do_multi.c
-+++ b/tools/do_multi.c
-@@ -9,16 +9,20 @@
- 
-     progname = basename(argv[0]);
- 
-+#ifdef AR_DEBUG
-     if(strcmp(progname, "80211debug") == 0)
- 	ret = a80211debug_init(argc, argv);
-+#endif
-     if(strcmp(progname, "80211stats") == 0)
- 	ret = a80211stats_init(argc, argv);
-     if(strcmp(progname, "athchans") == 0)
- 	ret = athchans_init(argc, argv);
-     if(strcmp(progname, "athctrl") == 0)
- 	ret =  athctrl_init(argc, argv);
-+#ifdef AR_DEBUG
-     if(strcmp(progname, "athdebug") == 0)
- 	ret =  athdebug_init(argc, argv);
-+#endif
-     if(strcmp(progname, "athkey") == 0)
- 	ret =  athkey_init(argc, argv);
-     if(strcmp(progname, "athstats") == 0)
---- a/tools/Makefile
-+++ b/tools/Makefile
-@@ -39,6 +39,10 @@
- 
- ATH_HAL = $(TOP)/ath_hal
- 
-+ifndef ATH_DEBUG
-+ATH_DEBUG=1
-+endif
-+
- #
- # Path to the HAL source code.
- #
-@@ -46,17 +50,22 @@
- HAL = $(TOP)/hal
- endif
- 
-+INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
-+CFLAGS = -g -O2 -Wall
-+ALL_CFLAGS = $(CFLAGS) $(INCS)
-+LDFLAGS =
- 
- PROGRAMS = athstats 80211stats athkey athchans athctrl \
--	athdebug 80211debug wlanconfig wpakey
-+	wlanconfig wpakey
-+
-+ifeq ($(ATH_DEBUG),1)
-+  PROGRAMS += athdebug 80211debug
-+  ALL_CFLAGS += -DAR_DEBUG
-+endif
- 
- OBJS = $(patsubst %,%.o,$(PROGRAMS)) ath_info/ath_info.o
- SUBDIRS = ath_info
- 
--INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
--CFLAGS = -g -O2 -Wall
--ALL_CFLAGS = $(CFLAGS) $(INCS)
--LDFLAGS =
- 
- all: all-subdirs compile
- 
---- a/ath/if_ath_hal.h
-+++ b/ath/if_ath_hal.h
-@@ -1263,6 +1263,7 @@
- 
-            tail -f /var/log/messages | sed -f hal_unmangle.sed 
-  */
-+#ifdef AR_DEBUG
- static inline void ath_hal_dump_map(struct ath_hal *ah)
- {
- #ifdef CONFIG_KALLSYMS
-@@ -1527,7 +1528,7 @@
- #endif				/* #ifndef CONFIG_KALLSYMS */
- 
- }
--
-+#endif
- #include "if_ath_hal_wrappers.h"
- #include "if_ath_hal_extensions.h"
- 
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -495,9 +495,10 @@
- 	/* inject a fake radar signal -- used while on a 802.11h DFS channels */
- 	unsigned int (*ic_test_radar)(struct ieee80211com *);
- 
-+#ifdef AR_DEBUG
- 	/* dump HAL */
- 	unsigned int (*ic_dump_hal_map)(struct ieee80211com *);
--
-+#endif
- 	/* DFS channel availability check time (in seconds) */
- 	void (*ic_set_dfs_cac_time)(struct ieee80211com *, unsigned int);
- 	unsigned int (*ic_get_dfs_cac_time)(struct ieee80211com *);
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -1557,6 +1557,7 @@
- 	return 0;
- }
- 
-+#ifdef AR_DEBUG
- static int 
- ieee80211_ioctl_hal_map(struct net_device *dev, struct iw_request_info *info,
-        void *w, char *extra)
-@@ -1567,7 +1568,7 @@
-        params[0] = ic->ic_dump_hal_map(ic);
-        return 0;
- }
--
-+#endif
- 
- static int
- ieee80211_ioctl_radar(struct net_device *dev, struct iw_request_info *info,
-@@ -5296,8 +5297,10 @@
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,   "getwmmparams" },
- 	{ IEEE80211_IOCTL_RADAR,
- 	  0, 0, "doth_radar" },
-+#ifdef AR_DEBUG
- 	{ IEEE80211_IOCTL_HALMAP,
- 	  0, 0, "dump_hal_map" },
-+#endif
- 	/*
- 	 * These depends on sub-ioctl support which added in version 12.
- 	 */
-@@ -5751,7 +5754,9 @@
- 	set_priv(IEEE80211_IOCTL_SETMLME, ieee80211_ioctl_setmlme),
- 	set_priv(IEEE80211_IOCTL_SETKEY, ieee80211_ioctl_setkey),
- 	set_priv(IEEE80211_IOCTL_DELKEY, ieee80211_ioctl_delkey),
-+#ifdef AR_DEBUG
- 	set_priv(IEEE80211_IOCTL_HALMAP, ieee80211_ioctl_hal_map),
-+#endif
- 	set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac),
- 	set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac),
- 	set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
---- a/ath/if_ath_debug.h
-+++ b/ath/if_ath_debug.h
-@@ -54,6 +54,10 @@
- 	ATH_DEBUG_GLOBAL	= (ATH_DEBUG_SKB|ATH_DEBUG_SKB_REF)
- };
- 
-+#define	EPRINTF(_sc, _fmt, ...) \
-+		printk(KERN_ERR "%s: %s: " _fmt, \
-+			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
-+
- #ifdef AR_DEBUG
- 
- /* DEBUG-ONLY DEFINITIONS */
-@@ -68,20 +72,9 @@
- 		ath_keyprint((_sc), __func__, _ix, _hk, _mac);		\
- } while (0)
- 
--#else /* #ifdef AR_DEBUG */
--
--#define	DFLAG_ISSET(sc, _m)		0
--#define	DPRINTF(sc, _m, _fmt, ...)
--#define	KEYPRINTF(sc, k, ix, mac)
--
--#endif /* #ifdef AR_DEBUG */
- 
- #define	IFF_DUMPPKTS(_sc, _m)   DFLAG_ISSET((_sc), (_m))
- 
--#define	EPRINTF(_sc, _fmt, ...) \
--		printk(KERN_ERR "%s: %s: " _fmt, \
--			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
--
- #define	WPRINTF(_sc, _fmt, ...) \
- 		printk(KERN_WARNING "%s: %s: " _fmt, \
- 			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
-@@ -89,5 +82,14 @@
- #define	IPRINTF(_sc, _fmt, ...) \
- 		printk(KERN_INFO "%s: %s: " _fmt, \
- 			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
-+#else
-+#define	DFLAG_ISSET(sc, _m)		0
-+#define	DPRINTF(sc, _m, _fmt, ...)
-+#define	KEYPRINTF(sc, k, ix, mac)
-+#define WPRINTF(...)
-+#define IPRINTF(...)
-+#define IFF_DUMPPKTS(...) 0
-+
-+#endif
- 
- #endif /* #ifndef _IF_ATH_DEBUG_H_ */
---- a/ath/if_ath_pci.c
-+++ b/ath/if_ath_pci.c
-@@ -134,8 +134,10 @@
- 	u16 vdevice;
- 	int i;
- 
--	if (pci_enable_device(pdev))
-+	if (pci_enable_device(pdev)) {
-+		printk(KERN_ERR "%s: failed to enable PCI device\n", dev_info);
- 		return -EIO;
-+	}
- 
- 	/* XXX 32-bit addressing only */
- 	if (pci_set_dma_mask(pdev, 0xffffffff)) {
-@@ -244,8 +246,10 @@
- 		sc->aps_sc.sc_ledpin = 1;
- 	}
- 
--	if (ath_attach(vdevice, dev, NULL) != 0)
-+	if ((i = ath_attach(vdevice, dev, NULL)) != 0) {
-+		printk(KERN_ERR "%s: ath_attach failed: %d\n", dev_info, i);
- 		goto bad4;
-+	}
- 
- 	athname = ath_hal_probe(id->vendor, vdevice);
- 	printk(KERN_INFO "%s: %s: %s: mem=0x%llx, irq=%d\n",
diff --git a/package/madwifi/patches-r3776/201-no_debug_extra.patch b/package/madwifi/patches-r3776/201-no_debug_extra.patch
deleted file mode 100644
index 0e26d5f39..000000000
--- a/package/madwifi/patches-r3776/201-no_debug_extra.patch
+++ /dev/null
@@ -1,33 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -423,8 +423,8 @@
- 		"defaults to '" DEF_RATE_CTL "'");
- MODULE_PARM_DESC(intmit, "Enable interference mitigation by default.  Default is 0.");
- 
--static int	ath_debug = 0;
- #ifdef AR_DEBUG
-+static int	ath_debug = 0;
- #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
- MODULE_PARM(ath_debug, "i");
- #else
-@@ -435,8 +435,8 @@
- static void ath_printtxbuf(const struct ath_buf *, int);
- #endif /* defined(AR_DEBUG) */
- 
--static int	ieee80211_debug = 0;
- #ifdef AR_DEBUG
-+static int	ieee80211_debug = 0;
- #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
- MODULE_PARM(ieee80211_debug, "i");
- #else
-@@ -853,8 +853,10 @@
- 	ic->ic_updateslot = ath_updateslot;
- 	atomic_set(&ic->ic_node_counter, 0);
- 	ic->ic_debug = 0;
-+#ifdef AR_DEBUG
- 	sc->sc_debug = (ath_debug & ~ATH_DEBUG_GLOBAL);
- 	sc->sc_default_ieee80211_debug = ieee80211_debug;
-+#endif
- 
- 	ic->ic_wme.wme_update = ath_wme_update;
- 	ic->ic_uapsd_flush = ath_uapsd_flush;
diff --git a/package/madwifi/patches-r3776/300-napi_polling.patch b/package/madwifi/patches-r3776/300-napi_polling.patch
deleted file mode 100644
index 27dd838db..000000000
--- a/package/madwifi/patches-r3776/300-napi_polling.patch
+++ /dev/null
@@ -1,529 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -182,7 +182,11 @@
- 	struct sk_buff *, int, int, u_int64_t);
- static void ath_setdefantenna(struct ath_softc *, u_int);
- static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);
--static void ath_rx_tasklet(TQUEUE_ARG);
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+static int ath_rx_poll(struct napi_struct *napi, int budget);
-+#else
-+static int ath_rx_poll(struct net_device *dev, int *budget);
-+#endif
- static int ath_hardstart(struct sk_buff *, struct net_device *);
- static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);
- #ifdef ATH_SUPERG_COMP
-@@ -331,6 +335,9 @@
- static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
- 		u_int32_t new_clamped_maxtxpower);
- 
-+static void ath_poll_disable(struct net_device *dev);
-+static void ath_poll_enable(struct net_device *dev);
-+
- static void ath_scanbufs(struct ath_softc *sc);
- static int ath_debug_iwpriv(struct ieee80211com *ic, 
- 		unsigned int param, unsigned int value);
-@@ -518,7 +525,6 @@
- 
- 	atomic_set(&sc->sc_txbuf_counter, 0);
- 
--	ATH_INIT_TQUEUE(&sc->sc_rxtq,		ath_rx_tasklet,		dev);
- 	ATH_INIT_TQUEUE(&sc->sc_txtq,		ath_tx_tasklet,		dev);
- 	ATH_INIT_TQUEUE(&sc->sc_bmisstq,	ath_bmiss_tasklet,	dev);
- 	ATH_INIT_TQUEUE(&sc->sc_bstucktq,	ath_bstuck_tasklet,	dev);
-@@ -833,6 +839,12 @@
- 	dev->set_mac_address = ath_set_mac_address;
- 	dev->change_mtu = ath_change_mtu;
- 	dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64);
-+#else
-+	dev->poll = ath_rx_poll;
-+	dev->weight = 64;
-+#endif
- #ifdef USE_HEADERLEN_RESV
- 	dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
- 				sizeof(struct llc) +
-@@ -1770,7 +1782,7 @@
- }
- 
- static void
--ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf)
-+ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf, int schedule)
- {
- 	struct ath_hal *ah = sc->sc_ah;
- 	struct ath_desc *ds;
-@@ -2252,8 +2264,25 @@
- 	}
- 
- 	/* If we got something to process, schedule rx queue to handle it */
--	if (count)
--		ATH_SCHEDULE_TQUEUE(&sc->sc_rxtq, pneedmark);
-+	if (count) {
-+		sc->sc_isr &= ~HAL_INT_RX;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+		if (netif_rx_schedule_prep(sc->sc_dev, &sc->sc_napi))
-+#else
-+		if (netif_rx_schedule_prep(sc->sc_dev))
-+#endif
-+		{
-+#ifndef ATH_PRECISE_TSF
-+			sc->sc_imask &= ~HAL_INT_RX;
-+			ath_hal_intrset(ah, sc->sc_imask);
-+#endif
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+			__netif_rx_schedule(sc->sc_dev, &sc->sc_napi);
-+#else
-+			__netif_rx_schedule(sc->sc_dev);
-+#endif
-+		}
-+	}
- 	ATH_RXBUF_UNLOCK_IRQ(sc);
- #undef PA2DESC
- }
-@@ -2343,6 +2372,7 @@
- 		(status & HAL_INT_GLOBAL)	? " HAL_INT_GLOBAL"	: ""
- 		);
- 
-+	sc->sc_isr = status;
- 	status &= sc->sc_imask;			/* discard unasked for bits */
- 	/* As soon as we know we have a real interrupt we intend to service, 
- 	 * we will check to see if we need an initial hardware TSF reading. 
-@@ -2400,7 +2430,7 @@
- 		}
- 		if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
- 			/* NB: Will schedule rx tasklet if necessary. */
--			ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf);
-+			ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf, 1);
- 		}
- 		if (status & HAL_INT_TX) {
- #ifdef ATH_SUPERG_DYNTURBO
-@@ -2426,6 +2456,11 @@
- 				}
- 			}
- #endif
-+			/* disable transmit interrupt */
-+			sc->sc_isr &= ~HAL_INT_TX;
-+			ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_TX);
-+			sc->sc_imask &= ~HAL_INT_TX;
-+
- 			ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
- 		}
- 		if (status & HAL_INT_BMISS) {
-@@ -2617,6 +2652,7 @@
- 	if (sc->sc_tx99 != NULL)
- 		sc->sc_tx99->start(sc->sc_tx99);
- #endif
-+	ath_poll_enable(dev);
- 
- done:
- 	ATH_UNLOCK(sc);
-@@ -2657,6 +2693,9 @@
- 		if (sc->sc_tx99 != NULL)
- 			sc->sc_tx99->stop(sc->sc_tx99);
- #endif
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+		ath_poll_disable(dev);
-+#endif
- 		netif_stop_queue(dev);	/* XXX re-enabled by ath_newstate */
- 		dev->flags &= ~IFF_RUNNING;	/* NB: avoid recursion */
- 		ieee80211_stop_running(ic);	/* stop all VAPs */
-@@ -4109,6 +4148,43 @@
- 	return ath_keyset(sc, k, mac, vap->iv_bss);
- }
- 
-+static void ath_poll_disable(struct net_device *dev)
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	struct ath_softc *sc = dev->priv;
-+#endif
-+
-+	/*
-+	 * XXX Using in_softirq is not right since we might
-+	 * be called from other soft irq contexts than
-+	 * ath_rx_poll
-+	 */
-+	if (!in_softirq()) {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+		napi_disable(&sc->sc_napi);
-+#else
-+		netif_poll_disable(dev);
-+#endif
-+	}
-+}
-+
-+static void ath_poll_enable(struct net_device *dev)
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	struct ath_softc *sc = dev->priv;
-+#endif
-+
-+	/* NB: see above */
-+	if (!in_softirq()) {
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+		napi_enable(&sc->sc_napi);
-+#else
-+		netif_poll_enable(dev);
-+#endif
-+	}
-+}
-+
-+
- /*
-  * Block/unblock tx+rx processing while a key change is done.
-  * We assume the caller serializes key management operations
-@@ -4119,33 +4195,23 @@
- ath_key_update_begin(struct ieee80211vap *vap)
- {
- 	struct net_device *dev = vap->iv_ic->ic_dev;
--	struct ath_softc *sc = dev->priv;
- 
--	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
- 	/*
- 	 * When called from the rx tasklet we cannot use
- 	 * tasklet_disable because it will block waiting
- 	 * for us to complete execution.
--	 *
--	 * XXX Using in_softirq is not right since we might
--	 * be called from other soft irq contexts than
--	 * ath_rx_tasklet.
- 	 */
--	if (!in_softirq())
--		tasklet_disable(&sc->sc_rxtq);
--	netif_stop_queue(dev);
-+	if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
-+		netif_stop_queue(dev);
- }
- 
- static void
- ath_key_update_end(struct ieee80211vap *vap)
- {
- 	struct net_device *dev = vap->iv_ic->ic_dev;
--	struct ath_softc *sc = dev->priv;
- 
--	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
--	netif_wake_queue(dev);
--	if (!in_softirq())		/* NB: see above */
--		tasklet_enable(&sc->sc_rxtq);
-+	if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
-+		netif_wake_queue(dev);
- }
- 
- /*
-@@ -6405,15 +6471,25 @@
- 	sc->sc_numrxotherant = 0;
- }
- 
--static void
--ath_rx_tasklet(TQUEUE_ARG data)
-+static int
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+ath_rx_poll(struct napi_struct *napi, int budget)
-+#else
-+ath_rx_poll(struct net_device *dev, int *budget)
-+#endif
- {
- #define	PA2DESC(_sc, _pa) \
- 	((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
- 		((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
--	struct net_device *dev = (struct net_device *)data;
--	struct ath_buf *bf;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	struct ath_softc *sc = container_of(napi, struct ath_softc, sc_napi);
-+	struct net_device *dev = sc->sc_dev;
-+	u_int rx_limit = budget;
-+#else
- 	struct ath_softc *sc = dev->priv;
-+	u_int rx_limit = min(dev->quota, *budget);
-+#endif
-+	struct ath_buf *bf;
- 	struct ieee80211com *ic = &sc->sc_ic;
- 	struct ath_hal *ah = sc ? sc->sc_ah : NULL;
- 	struct ath_desc *ds;
-@@ -6421,6 +6497,7 @@
- 	struct ieee80211_node *ni;
- 	struct sk_buff *skb = NULL;
- 	unsigned int len, phyerr, mic_fail = 0;
-+	unsigned int early_stop = 0;
- 	int type = -1; /* undefined */
- 	int init_ret = 0;
- 	int bf_processed = 0;
-@@ -6428,6 +6505,7 @@
- 	int errors	 = 0;
- 
- 	DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s started...\n", __func__);
-+process_rx_again:
- 	do {
- 		/* Get next RX buffer pending processing by RX tasklet...
- 		 *  
-@@ -6457,6 +6535,10 @@
- 			break;
- 
- 		bf_processed++;
-+		if (rx_limit-- < 0) {
-+			early_stop = 1;
-+			break;
-+		}
- 		ds  = bf->bf_desc;
- 
- #ifdef AR_DEBUG
-@@ -6491,6 +6573,7 @@
- 				sc->sc_stats.ast_rx_phyerr++;
- 				phyerr = rs->rs_phyerr & 0x1f;
- 				sc->sc_stats.ast_rx_phy[phyerr]++;
-+				goto rx_next;
- 			}
- 			if (rs->rs_status & HAL_RXERR_DECRYPT) {
- 				/* Decrypt error.  If the error occurred
-@@ -6689,6 +6772,33 @@
- 		STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
- 		ATH_RXBUF_UNLOCK_IRQ(sc);
- 	} while (1);
-+	if (!early_stop) {
-+		unsigned long flags;
-+		/* Check if more data is received while we were
-+		 * processing the descriptor chain.
-+		 */
-+#ifndef ATH_PRECISE_TSF
-+		local_irq_save(flags);
-+		if (sc->sc_isr & HAL_INT_RX) {
-+			u_int64_t hw_tsf = ath_hal_gettsf64(ah);
-+			sc->sc_isr &= ~HAL_INT_RX;
-+			local_irq_restore(flags);
-+			ath_intr_process_rx_descriptors(sc, NULL, hw_tsf, 0);
-+			goto process_rx_again;
-+		}
-+		sc->sc_imask |= HAL_INT_RX;
-+		ath_hal_intrset(ah, sc->sc_imask);
-+		local_irq_restore(flags);
-+#endif
-+	}
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	netif_rx_complete(dev, napi);
-+#else
-+	netif_rx_complete(dev);
-+	*budget -= bf_processed;
-+	dev->quota -= bf_processed;
-+#endif
- 
- 	if (sc->sc_useintmit) 
- 		ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
-@@ -6701,6 +6811,12 @@
- 		" %d rx buf processed. %d were errors. %d skb accepted.\n",
- 		__func__, bf_processed, errors, skb_accepted);
- #undef PA2DESC
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	return bf_processed;
-+#else
-+	return early_stop;
-+#endif
- }
- 
- #ifdef ATH_SUPERG_XR
-@@ -8306,12 +8422,24 @@
- {
- 	struct net_device *dev = (struct net_device *)data;
- 	struct ath_softc *sc = dev->priv;
-+	unsigned long flags;
- 
-+process_tx_again:
- 	if (txqactive(sc->sc_ah, 0))
- 		ath_tx_processq(sc, &sc->sc_txq[0]);
- 	if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
- 		ath_tx_processq(sc, sc->sc_cabq);
- 
-+	local_irq_save(flags);
-+	if (sc->sc_isr & HAL_INT_TX) {
-+		sc->sc_isr &= ~HAL_INT_TX;
-+		local_irq_restore(flags);
-+		goto process_tx_again;
-+	}
-+	sc->sc_imask |= HAL_INT_TX;
-+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
-+	local_irq_restore(flags);
-+
- 	netif_wake_queue(dev);
- 
- 	if (sc->sc_softled)
-@@ -8327,7 +8455,9 @@
- {
- 	struct net_device *dev = (struct net_device *)data;
- 	struct ath_softc *sc = dev->priv;
-+	unsigned long flags;
- 
-+process_tx_again:
- 	/*
- 	 * Process each active queue.
- 	 */
-@@ -8357,6 +8487,16 @@
- 	if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
- 		ath_tx_processq(sc, sc->sc_uapsdq);
- 
-+	local_irq_save(flags);
-+	if (sc->sc_isr & HAL_INT_TX) {
-+		sc->sc_isr &= ~HAL_INT_TX;
-+		local_irq_restore(flags);
-+		goto process_tx_again;
-+	}
-+	sc->sc_imask |= HAL_INT_TX;
-+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
-+	local_irq_restore(flags);
-+
- 	netif_wake_queue(dev);
- 
- 	if (sc->sc_softled)
-@@ -10322,9 +10462,9 @@
- 	dev->mtu = mtu;
- 	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
- 		/* NB: the rx buffers may need to be reallocated */
--		tasklet_disable(&sc->sc_rxtq);
-+		ath_poll_disable(dev);
- 		error = ath_reset(dev);
--		tasklet_enable(&sc->sc_rxtq);
-+		ath_poll_enable(dev);
- 	}
- 	ATH_UNLOCK(sc);
- 
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -56,6 +56,10 @@
- # include	<asm/bitops.h>
- #endif
- 
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-+#define irqs_disabled()			0
-+#endif
-+
- /*
-  * Deduce if tasklets are available.  If not then
-  * fall back to using the immediate work queue.
-@@ -644,6 +648,9 @@
- struct ath_softc {
- 	struct ieee80211com sc_ic;		/* NB: must be first */
- 	struct net_device *sc_dev;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
-+	struct napi_struct sc_napi;
-+#endif
- 	void __iomem *sc_iobase;		/* address of the device */
- 	struct semaphore sc_lock;		/* dev-level lock */
- 	struct net_device_stats	sc_devstats;	/* device statistics */
-@@ -756,7 +763,6 @@
- 	struct ath_buf *sc_rxbufcur;		/* current rx buffer */
- 	u_int32_t *sc_rxlink;			/* link ptr in last RX desc */
- 	spinlock_t sc_rxbuflock;
--	struct ATH_TQ_STRUCT sc_rxtq;		/* rx intr tasklet */
- 	struct ATH_TQ_STRUCT sc_rxorntq;	/* rxorn intr tasklet */
- 	u_int16_t sc_cachelsz;			/* cache line size */
- 
-@@ -769,6 +775,7 @@
- 	u_int sc_txintrperiod;			/* tx interrupt batching */
- 	struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
- 	struct ath_txq *sc_ac2q[WME_NUM_AC];	/* WME AC -> h/w qnum */
-+	HAL_INT sc_isr;				/* unmasked ISR state */
- 	struct ATH_TQ_STRUCT sc_txtq;		/* tx intr tasklet */
- 	u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN];
- 	struct ath_descdma sc_bdma;		/* beacon descriptors */
-@@ -888,6 +895,8 @@
- #define	ATH_TXBUF_LOCK_CHECK(_sc)
- #endif
- 
-+#define ATH_DISABLE_INTR		local_irq_disable
-+#define ATH_ENABLE_INTR 		local_irq_enable
- 
- #define	ATH_RXBUF_LOCK_INIT(_sc)	spin_lock_init(&(_sc)->sc_rxbuflock)
- #define	ATH_RXBUF_LOCK_DESTROY(_sc)
---- a/net80211/ieee80211_skb.c
-+++ b/net80211/ieee80211_skb.c
-@@ -73,7 +73,7 @@
- #undef dev_queue_xmit
- #undef kfree_skb
- #undef kfree_skb_fast
--#undef netif_rx
-+#undef netif_receive_skb
- #undef pskb_copy
- #undef skb_clone
- #undef skb_copy
-@@ -581,8 +581,8 @@
- 		grp, vlan_tag);
- }
- 
--int netif_rx_debug(struct sk_buff *skb, const char *func, int line) {
--	return netif_rx(untrack_skb(skb, 0, __func__, __LINE__));
-+int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line) {
-+	return netif_receive_skb(untrack_skb(skb, 0, __func__, __LINE__));
- }
- 
- struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
-@@ -707,7 +707,7 @@
- }
- 
- EXPORT_SYMBOL(vlan_hwaccel_rx_debug);
--EXPORT_SYMBOL(netif_rx_debug);
-+EXPORT_SYMBOL(netif_receive_skb_debug);
- EXPORT_SYMBOL(alloc_skb_debug);
- EXPORT_SYMBOL(dev_alloc_skb_debug);
- EXPORT_SYMBOL(skb_clone_debug);
---- a/net80211/ieee80211_skb.h
-+++ b/net80211/ieee80211_skb.h
-@@ -115,7 +115,7 @@
- 
- int vlan_hwaccel_rx_debug(struct sk_buff *skb, struct vlan_group *grp,
- 		unsigned short vlan_tag, const char *func, int line);
--int netif_rx_debug(struct sk_buff *skb, const char *func, int line);
-+int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line);
- struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
- 		const char *func, int line);
- struct sk_buff *dev_alloc_skb_debug(unsigned int length,
-@@ -150,7 +150,7 @@
- #undef dev_queue_xmit
- #undef kfree_skb
- #undef kfree_skb_fast
--#undef netif_rx
-+#undef netif_receive_skb
- #undef pskb_copy
- #undef skb_clone
- #undef skb_copy
-@@ -167,8 +167,8 @@
- 	skb_copy_expand_debug(_skb, _newheadroom, _newtailroom, _gfp_mask, __func__, __LINE__)
- #define vlan_hwaccel_rx(_skb, _grp, _tag) \
- 	vlan_hwaccel_rx_debug(_skb, _grp, _tag, __func__, __LINE__)
--#define netif_rx(_skb) \
--	netif_rx_debug(_skb, __func__, __LINE__)
-+#define netif_receive_skb(_skb) \
-+	netif_receive_skb_debug(_skb, __func__, __LINE__)
- #define	alloc_skb(_length, _gfp_mask) \
- 	alloc_skb_debug(_length, _gfp_mask, __func__, __LINE__)
- #define	dev_alloc_skb(_length) \
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -1185,7 +1185,7 @@
- 			ret = vlan_hwaccel_rx(skb,
- 					vap->iv_vlgrp, ni->ni_vlan);
- 		else
--			ret = netif_rx(skb);
-+			ret = netif_receive_skb(skb);
- 		if (ret == NET_RX_DROP)
- 			vap->iv_devstats.rx_dropped++;
- 		if (tni != NULL)
-@@ -2285,7 +2285,7 @@
- 
- 		if (SKB_NI(skb1) != NULL)
- 			ieee80211_unref_node(&SKB_NI(skb1));
--		if (netif_rx(skb1) == NET_RX_DROP)
-+		if (netif_receive_skb(skb1) == NET_RX_DROP)
- 			vap->iv_devstats.rx_dropped++;
- 	}
- }
---- a/net80211/ieee80211_monitor.c
-+++ b/net80211/ieee80211_monitor.c
-@@ -580,7 +580,7 @@
- 
- 			if (SKB_NI(skb1) != NULL)
- 				ieee80211_unref_node(&SKB_NI(skb1));
--			if (netif_rx(skb1) == NET_RX_DROP)
-+			if (netif_receive_skb(skb1) == NET_RX_DROP)
- 				vap->iv_devstats.rx_dropped++;
- 			skb1 = NULL;
- 		}
diff --git a/package/madwifi/patches-r3776/301-pureg_fix.patch b/package/madwifi/patches-r3776/301-pureg_fix.patch
deleted file mode 100644
index fb6cefe36..000000000
--- a/package/madwifi/patches-r3776/301-pureg_fix.patch
+++ /dev/null
@@ -1,168 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -4251,7 +4251,9 @@
- 		rfilt |= HAL_RX_FILTER_PROM;
- 	if (ic->ic_opmode == IEEE80211_M_STA ||
- 	    sc->sc_opmode == HAL_M_IBSS ||	/* NB: AHDEMO too */
--	    (sc->sc_nostabeacons) || sc->sc_scanning)
-+	    (sc->sc_nostabeacons) || sc->sc_scanning ||
-+		((ic->ic_opmode == IEEE80211_M_HOSTAP) &&
-+		 (ic->ic_protmode != IEEE80211_PROT_NONE)))
- 		rfilt |= HAL_RX_FILTER_BEACON;
- 	if (sc->sc_nmonvaps > 0)
- 		rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -325,11 +325,12 @@
- 				bssid = wh->i_addr3;
- 			}
- 			/*
--			 * Validate the bssid.
-+			 * Validate the bssid. Let beacons get through though for 11g protection mode.
- 			 */
--#ifdef ATH_SUPERG_XR
- 			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
--			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
-+			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast) &&
-+				(subtype != IEEE80211_FC0_SUBTYPE_BEACON)) {
-+#ifdef ATH_SUPERG_XR
- 				/*
- 				 * allow MGT frames to vap->iv_xrvap.
- 				 * this will allow roaming between  XR and normal vaps
-@@ -345,18 +346,14 @@
- 					vap->iv_stats.is_rx_wrongbss++;
- 					goto out;
- 				}
--			}
- #else
--			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
--			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
- 				/* not interested in */
- 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
- 					bssid, NULL, "%s", "not to bss");
- 				vap->iv_stats.is_rx_wrongbss++;
- 				goto out;
--			}
--
- #endif
-+			}
- 			break;
- 		case IEEE80211_M_WDS:
- 			if (skb->len < sizeof(struct ieee80211_frame_addr4)) {
-@@ -3019,7 +3016,7 @@
- 	u_int8_t *frm, *efrm;
- 	u_int8_t *ssid, *rates, *xrates, *suppchan, *wpa, *rsn, *wme, *ath;
- 	u_int8_t rate;
--	int reassoc, resp, allocbs = 0;
-+	int reassoc, resp, allocbs = 0, has_erp = 0;
- 	u_int8_t qosinfo;
- 
- 	if (ni_or_null == NULL)
-@@ -3049,11 +3046,15 @@
- 		 *    o station mode when associated (to collect state
- 		 *      updates such as 802.11g slot time), or
- 		 *    o adhoc mode (to discover neighbors)
-+		 *    o ap mode in protection mode (beacons only)
- 		 * Frames otherwise received are discarded.
- 		 */
- 		if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
- 		    (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
--		    vap->iv_opmode == IEEE80211_M_IBSS)) {
-+		    (vap->iv_opmode == IEEE80211_M_IBSS) ||
-+			((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
-+			 (vap->iv_opmode == IEEE80211_M_HOSTAP) &&
-+			 (ic->ic_protmode != IEEE80211_PROT_NONE)))) {
- 			vap->iv_stats.is_rx_mgtdiscard++;
- 			return 0;
- 		}
-@@ -3137,6 +3138,7 @@
- 					break;
- 				}
- 				scan.erp = frm[2];
-+				has_erp = 1;
- 				break;
- 			case IEEE80211_ELEMID_RSN:
- 				scan.rsn = frm;
-@@ -3374,6 +3376,20 @@
- 				ieee80211_bg_scan(vap);
- 			return 0;
- 		}
-+
-+		/* Update AP protection mode when in 11G mode */
-+		if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
-+			IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
-+
-+			/* Assume no ERP IE == 11b AP */
-+			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
-+				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
-+
-+				ic->ic_flags |= IEEE80211_F_USEPROT;
-+				ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+			}
-+		}
-+
- 		/*
- 		 * If scanning, just pass information to the scan module.
- 		 */
---- a/net80211/ieee80211_node.c
-+++ b/net80211/ieee80211_node.c
-@@ -345,10 +345,16 @@
- 	/* Update country ie information */
- 	ieee80211_build_countryie(ic);
- 
--	if (IEEE80211_IS_CHAN_HALF(chan))
-+	if (IEEE80211_IS_CHAN_HALF(chan)) {
- 		ni->ni_rates = ic->ic_sup_half_rates;
--	else if (IEEE80211_IS_CHAN_QUARTER(chan))
-+	} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
- 		ni->ni_rates = ic->ic_sup_quarter_rates;
-+	}
-+
-+	if ((vap->iv_flags & IEEE80211_F_PUREG) &&
-+		IEEE80211_IS_CHAN_ANYG(chan)) {
-+		ieee80211_setpuregbasicrates(&ni->ni_rates);
-+	}
- 
- 	(void) ieee80211_sta_join1(PASS_NODE(ni));
- }
---- a/net80211/ieee80211_proto.c
-+++ b/net80211/ieee80211_proto.c
-@@ -599,6 +599,28 @@
- 	{ 4, { 2, 4, 11, 22 } },	/* IEEE80211_MODE_TURBO_G (mixed b/g) */
- };
- 
-+static const struct ieee80211_rateset basicpureg[] = {
-+    { 7, {2, 4, 11, 22, 12, 24, 48 } },
-+};
-+
-+/*
-+ * Mark basic rates for the 11g rate table based on the pureg setting
-+ */
-+void
-+ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs)
-+{
-+	int i, j;
-+
-+	for (i = 0; i < rs->rs_nrates; i++) {
-+		rs->rs_rates[i] &= IEEE80211_RATE_VAL;
-+		for (j = 0; j < basicpureg[0].rs_nrates; j++)
-+			if (basicpureg[0].rs_rates[j] == rs->rs_rates[i]) {
-+				rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
-+				break;
-+			}
-+	}
-+}
-+
- /*
-  * Mark the basic rates for the 11g rate table based on the
-  * specified mode.  For 11b compatibility we mark only 11b
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -712,6 +712,7 @@
- void ieee80211_build_sc_ie(struct ieee80211com *);
- void ieee80211_dfs_action(struct ieee80211com *);
- void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *);
-+void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs);
- 
- /*
-  * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers.
diff --git a/package/madwifi/patches-r3776/302-noise_get.patch b/package/madwifi/patches-r3776/302-noise_get.patch
deleted file mode 100644
index 8c69ca24f..000000000
--- a/package/madwifi/patches-r3776/302-noise_get.patch
+++ /dev/null
@@ -1,38 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8997,6 +8997,7 @@
- 			ATH_LONG_CALINTERVAL_SECS : 
- 			ATH_SHORT_CALINTERVAL_SECS;
- 	}
-+	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
- 
- 	DPRINTF(sc, ATH_DEBUG_CALIBRATE, "Channel %u [flags=%04x] -- IQ %s.\n",
- 		sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
-@@ -9052,6 +9053,7 @@
- 	struct ath_softc *sc = dev->priv;
- 
- 	(void) ath_chan_set(sc, ic->ic_curchan);
-+	ic->ic_channoise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
- 	/*
- 	 * If we are returning to our bss channel then mark state
- 	 * so the next recv'd beacon's TSF will be used to sync the
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -4396,6 +4396,7 @@
- 	si->isi_state = ni->ni_flags;
- 	si->isi_authmode = ni->ni_authmode;
- 	si->isi_rssi = ic->ic_node_getrssi(ni);
-+	si->isi_noise = ic->ic_channoise;
- 	si->isi_capinfo = ni->ni_capinfo;
- 	si->isi_athflags = ni->ni_ath_flags;
- 	si->isi_erp = ni->ni_erp;
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -312,6 +312,7 @@
- 	u_int16_t isi_state;		/* state flags */
- 	u_int8_t isi_authmode;		/* authentication algorithm */
- 	u_int8_t isi_rssi;
-+	int8_t isi_noise;
- 	u_int16_t isi_capinfo;		/* capabilities */
- 	u_int8_t isi_athflags;		/* Atheros capabilities */
- 	u_int8_t isi_erp;		/* ERP element */
diff --git a/package/madwifi/patches-r3776/303-bssid_alloc.patch b/package/madwifi/patches-r3776/303-bssid_alloc.patch
deleted file mode 100644
index 43e0d6dcf..000000000
--- a/package/madwifi/patches-r3776/303-bssid_alloc.patch
+++ /dev/null
@@ -1,40 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -1347,11 +1347,12 @@
- 			TAILQ_FOREACH(v, &ic->ic_vaps, iv_next)
- 				id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr));
- 
--			for (id = 1; id < ath_maxvaps; id++) {
-+			for (id = 0; id < ath_maxvaps; id++) {
- 				/* Get the first available slot. */
- 				if ((id_mask & (1 << id)) == 0) {
- 					ATH_SET_VAP_BSSID(vap->iv_myaddr, id);
- 					ATH_SET_VAP_BSSID(vap->iv_bssid, id);
-+					sc->sc_bclast = id;
- 					break;
- 				}
- 			}
-@@ -1359,7 +1360,12 @@
- 			EPRINTF(sc, "Unique BSSID requested on HW that does"
- 				"does not support the necessary features.");
- 		}
-+	} else {
-+		/* share the BSSID of the last created VAP */
-+		ATH_SET_VAP_BSSID(vap->iv_myaddr, sc->sc_bclast);
-+		ATH_SET_VAP_BSSID(vap->iv_bssid, sc->sc_bclast);
- 	}
-+
- 	avp->av_bslot = -1;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
- 	atomic_set(&avp->av_beacon_alloc, 0);
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -802,7 +802,7 @@
- 	} sc_updateslot;			/* slot time update fsm */
- 	int sc_slotupdate;			/* slot to next advance fsm */
- 	struct ieee80211vap **sc_bslot;		/* beacon xmit slots */
--	int sc_bnext;				/* next slot for beacon xmit */
-+	int sc_bclast;				/* last used slot for beacon xmit */
- 
- 	int sc_beacon_cal;			/* use beacon timer for calibration */
- 	long unsigned int sc_calinterval_sec;	/* current interval for calibration (in seconds) */
diff --git a/package/madwifi/patches-r3776/304-erp_update.patch b/package/madwifi/patches-r3776/304-erp_update.patch
deleted file mode 100644
index be64b9537..000000000
--- a/package/madwifi/patches-r3776/304-erp_update.patch
+++ /dev/null
@@ -1,68 +0,0 @@
---- a/net80211/ieee80211_beacon.c
-+++ b/net80211/ieee80211_beacon.c
-@@ -544,10 +544,10 @@
- 			vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
- 		}
- #endif
--		if ((ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) && 
-+		if ((vap->iv_flags_ext & IEEE80211_FEXT_ERPUPDATE) &&
- 				(bo->bo_erp != NULL)) {
- 			(void)ieee80211_add_erp(bo->bo_erp, ic);
--			ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
-+			vap->iv_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
- 		}
- 	}
- 	/* if it is a mode change beacon for dynamic turbo case */
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -3384,9 +3384,12 @@
- 			/* Assume no ERP IE == 11b AP */
- 			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
- 				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
-+				struct ieee80211vap *tmpvap;
- 
- 				ic->ic_flags |= IEEE80211_F_USEPROT;
--				ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+				TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
-+					tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+				}
- 			}
- 		}
- 
---- a/net80211/ieee80211_node.c
-+++ b/net80211/ieee80211_node.c
-@@ -1741,8 +1741,12 @@
- 		}
- 
- 		/* Update ERP element if this is first non ERP station */
--		if (ic->ic_nonerpsta == 1)
--			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+		if (ic->ic_nonerpsta == 1) {
-+			struct ieee80211vap *tmpvap;
-+			TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
-+				tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+			}
-+		}
- 	} else
- 		ni->ni_flags |= IEEE80211_NODE_ERP;
- }
-@@ -1945,6 +1949,8 @@
- 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
- 			"non-ERP station leaves, count now %d", ic->ic_nonerpsta);
- 		if (ic->ic_nonerpsta == 0) {
-+			struct ieee80211vap *tmpvap;
-+
- 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
- 				"%s: disable use of protection\n", __func__);
- 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
-@@ -1956,7 +1962,9 @@
- 				ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
- 				ic->ic_flags &= ~IEEE80211_F_USEBARKER;
- 			}
--			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+			TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
-+				tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+			}
- 		}
- 	}
- }
diff --git a/package/madwifi/patches-r3776/305-bssid_mask.patch b/package/madwifi/patches-r3776/305-bssid_mask.patch
deleted file mode 100644
index bc02462a3..000000000
--- a/package/madwifi/patches-r3776/305-bssid_mask.patch
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8717,6 +8717,10 @@
- 
- 	sc->sc_rxbufcur = NULL;
- 
-+	/* configure bssid mask */
-+	if (sc->sc_hasbmask)
-+		ath_hal_setbssidmask(ah, sc->sc_bssidmask);
-+
- 	bf = STAILQ_FIRST(&sc->sc_rxbuf);
- 	ath_hal_putrxbuf(ah, bf->bf_daddr);
- 	ath_hal_rxena(ah);		/* enable recv descriptors */
diff --git a/package/madwifi/patches-r3776/306-queue.patch b/package/madwifi/patches-r3776/306-queue.patch
deleted file mode 100644
index 3341f01b8..000000000
--- a/package/madwifi/patches-r3776/306-queue.patch
+++ /dev/null
@@ -1,42 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8448,8 +8448,6 @@
- 	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
- 	local_irq_restore(flags);
- 
--	netif_wake_queue(dev);
--
- 	if (sc->sc_softled)
- 		ath_led_event(sc, ATH_LED_TX);
- }
-@@ -8505,8 +8503,6 @@
- 	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
- 	local_irq_restore(flags);
- 
--	netif_wake_queue(dev);
--
- 	if (sc->sc_softled)
- 		ath_led_event(sc, ATH_LED_TX);
- }
-@@ -8537,7 +8533,9 @@
- 				STAILQ_FIRST(&sc->sc_cabq->axq_q) ? "not setup" : "empty");
- 		}
- 	}
--	netif_wake_queue(dev);
-+
-+	if (ath_get_buffers_available(sc) > ATH_TXBUF_MGT_RESERVED)
-+		netif_wake_queue(dev);
- 
- 	if (sc->sc_softled)
- 		ath_led_event(sc, ATH_LED_TX);
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -1116,7 +1116,7 @@
- 	    (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
- 		struct sk_buff *skb1 = NULL;
- 
--		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
-+		if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
- 			/* Create a SKB for the BSS to send out. */
- 			skb1 = skb_copy(skb, GFP_ATOMIC);
- 			if (skb1)
diff --git a/package/madwifi/patches-r3776/307-maxrate.patch b/package/madwifi/patches-r3776/307-maxrate.patch
deleted file mode 100644
index a5a1db02f..000000000
--- a/package/madwifi/patches-r3776/307-maxrate.patch
+++ /dev/null
@@ -1,96 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -1299,6 +1299,7 @@
- 	vap->iv_key_set = ath_key_set;
- 	vap->iv_key_update_begin = ath_key_update_begin;
- 	vap->iv_key_update_end = ath_key_update_end;
-+	vap->iv_maxrateindex = 0;
- 	if (sc->sc_default_ieee80211_debug) {
- 		/* User specified defaults for new VAPs were provided, so
- 		 * use those (only). */
---- a/ath_rate/sample/sample.c
-+++ b/ath_rate/sample/sample.c
-@@ -838,7 +838,12 @@
- 	}
- 	sn->static_rate_ndx = -1;
- 
--	sn->num_rates = ni->ni_rates.rs_nrates;
-+	if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
-+	    || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
-+		sn->num_rates = ni->ni_rates.rs_nrates;
-+	else
-+		sn->num_rates = vap->iv_maxrateindex;
-+
- 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
- 		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
- 		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -291,6 +291,7 @@
- 	struct ieee80211_spy iv_spy;         		/* IWSPY support */
- 	struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
- 	u_int32_t app_filter;				/* filters which management frames are forwarded to app */
-+	int iv_maxrateindex;
- };
- 
- /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -2873,6 +2873,12 @@
- 		else
- 			ic->ic_flags_ext &= ~IEEE80211_FEXT_MARKDFS;
- 		break;
-+	case IEEE80211_PARAM_MAXRATE:
-+		if (value > 0)
-+			vap->iv_maxrateindex = value;
-+		else
-+			vap->iv_maxrateindex = 0;
-+		break;
- #ifdef ATH_REVERSE_ENGINEERING
- 	case IEEE80211_PARAM_DUMPREGS:
- 		ieee80211_dump_registers(dev, info, w, extra);
-@@ -3211,6 +3217,9 @@
- 		else
- 			param[0] = 0;
- 		break;
-+	case IEEE80211_PARAM_MAXRATE:
-+		param[0] = vap->iv_maxrateindex;
-+		break;
- 	default:
- 		return -EOPNOTSUPP;
- 	}
-@@ -5666,6 +5675,10 @@
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_scanbufs" },
- 	{ IEEE80211_PARAM_LEAKTXBUFS,
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_leaktxbufs" },
-+	{IEEE80211_PARAM_MAXRATE,
-+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
-+	{IEEE80211_PARAM_MAXRATE,
-+	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
- 	
- #ifdef ATH_REVERSE_ENGINEERING
- 	/*
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -650,6 +650,7 @@
- 	IEEE80211_PARAM_RESETTXBUFS		= 80,   /* Reset transmit DMA */
- 	IEEE80211_PARAM_SCANBUFS		= 81,	/* Heap analysis for TX DMA */
- 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
-+	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
- };
- 
- #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
---- a/ath_rate/minstrel/minstrel.c
-+++ b/ath_rate/minstrel/minstrel.c
-@@ -644,6 +644,11 @@
- 		return;
- 	}
- 	sn->static_rate_ndx = -1;
-+	if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
-+	    || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
-+		sn->num_rates = ni->ni_rates.rs_nrates;
-+	else
-+		sn->num_rates = vap->iv_maxrateindex;
- 
- 	sn->num_rates = ni->ni_rates.rs_nrates;
- 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
diff --git a/package/madwifi/patches-r3776/308-minrate.patch b/package/madwifi/patches-r3776/308-minrate.patch
deleted file mode 100644
index 8e7b6066a..000000000
--- a/package/madwifi/patches-r3776/308-minrate.patch
+++ /dev/null
@@ -1,112 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -1300,6 +1300,7 @@
- 	vap->iv_key_update_begin = ath_key_update_begin;
- 	vap->iv_key_update_end = ath_key_update_end;
- 	vap->iv_maxrateindex = 0;
-+	vap->iv_minrateindex = 0;
- 	if (sc->sc_default_ieee80211_debug) {
- 		/* User specified defaults for new VAPs were provided, so
- 		 * use those (only). */
---- a/ath_rate/minstrel/minstrel.c
-+++ b/ath_rate/minstrel/minstrel.c
-@@ -652,6 +652,8 @@
- 
- 	sn->num_rates = ni->ni_rates.rs_nrates;
- 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
-+		int idx = x;
-+
- 		sn->rs_rateattempts 	[x] = 0;
- 		sn->rs_thisprob 	[x] = 0;
- 		sn->rs_ratesuccess 	[x] = 0;
-@@ -662,8 +664,12 @@
- 		sn->rs_att_hist 	[x] = 0;
- 		sn->rs_this_tp 		[x] = 0;
- 
--		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
--		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
-+		if (vap->iv_minrateindex && (vap->iv_minrateindex <
-+				ni->ni_rates.rs_nrates))
-+			idx = vap->iv_minrateindex;
-+
-+		sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
-+		sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
- 		if (sn->rates[x].rix == 0xff) {
- 			DPRINTF(sc, "%s: %s ignore bogus rix at %d\n",
- 				dev_info, __func__, x);
---- a/ath_rate/sample/sample.c
-+++ b/ath_rate/sample/sample.c
-@@ -845,8 +845,15 @@
- 		sn->num_rates = vap->iv_maxrateindex;
- 
- 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
--		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
--		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
-+		int idx = x;
-+
-+		if (vap->iv_minrateindex && vap->iv_minrateindex <
-+				ni->ni_rates.rs_nrates)
-+			idx = vap->iv_minrateindex;
-+
-+		sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
-+		sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
-+
- 		if (sn->rates[x].rix == 0xff) {
- 			DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s ignore bogus rix at %u\n",
- 				dev_info, __func__, x);
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -651,6 +651,7 @@
- 	IEEE80211_PARAM_SCANBUFS		= 81,	/* Heap analysis for TX DMA */
- 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
- 	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
-+	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
- };
- 
- #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -292,6 +292,7 @@
- 	struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
- 	u_int32_t app_filter;				/* filters which management frames are forwarded to app */
- 	int iv_maxrateindex;
-+	int iv_minrateindex;
- };
- 
- /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -2879,6 +2879,12 @@
- 		else
- 			vap->iv_maxrateindex = 0;
- 		break;
-+	case IEEE80211_PARAM_MINRATE:
-+		if (value > 0)
-+			vap->iv_minrateindex = value;
-+		else
-+			vap->iv_minrateindex = 0;
-+		break;
- #ifdef ATH_REVERSE_ENGINEERING
- 	case IEEE80211_PARAM_DUMPREGS:
- 		ieee80211_dump_registers(dev, info, w, extra);
-@@ -3220,6 +3226,9 @@
- 	case IEEE80211_PARAM_MAXRATE:
- 		param[0] = vap->iv_maxrateindex;
- 		break;
-+	case IEEE80211_PARAM_MINRATE:
-+		param[0] = vap->iv_minrateindex;
-+		break;
- 	default:
- 		return -EOPNOTSUPP;
- 	}
-@@ -5679,6 +5688,10 @@
- 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
- 	{IEEE80211_PARAM_MAXRATE,
- 	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
-+	{IEEE80211_PARAM_MINRATE,
-+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
-+	{IEEE80211_PARAM_MINRATE,
-+	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
- 	
- #ifdef ATH_REVERSE_ENGINEERING
- 	/*
diff --git a/package/madwifi/patches-r3776/309-performance.patch b/package/madwifi/patches-r3776/309-performance.patch
deleted file mode 100644
index ec2208525..000000000
--- a/package/madwifi/patches-r3776/309-performance.patch
+++ /dev/null
@@ -1,215 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -3334,7 +3334,6 @@
- 	struct ath_softc *sc = dev->priv;
- 	struct ieee80211_node *ni = NULL;
- 	struct ath_buf *bf = NULL;
--	struct ether_header *eh;
- 	ath_bufhead bf_head;
- 	struct ath_buf *tbf;
- 	struct sk_buff *tskb;
-@@ -3349,6 +3348,7 @@
- 	*/
- 	int requeue = 0;
- #ifdef ATH_SUPERG_FF
-+	struct ether_header *eh;
- 	unsigned int pktlen;
- 	struct ieee80211com *ic = &sc->sc_ic;
- 	struct ath_txq *txq = NULL;
---- a/net80211/ieee80211_output.c
-+++ b/net80211/ieee80211_output.c
-@@ -280,7 +280,7 @@
- 	 * normal vap. */
- 	if (vap->iv_xrvap && (ni == vap->iv_bss) &&
- 	    vap->iv_xrvap->iv_sta_assoc) {
--		struct sk_buff *skb1 = skb_copy(skb, GFP_ATOMIC);
-+		struct sk_buff *skb1 = skb_clone(skb, GFP_ATOMIC);
- 		if (skb1) {
- 			memset(SKB_CB(skb1), 0, sizeof(struct ieee80211_cb));
- #ifdef IEEE80211_DEBUG_REFCNT
-@@ -561,7 +561,7 @@
- 	struct ieee80211_key *key, struct sk_buff *skb, int ismulticast)
- {
- 	/* XXX pre-calculate per node? */
--	int need_headroom = LLC_SNAPFRAMELEN + hdrsize + IEEE80211_ADDR_LEN;
-+	int need_headroom = LLC_SNAPFRAMELEN + hdrsize;
- 	int need_tailroom = 0;
- #ifdef ATH_SUPERG_FF
- 	int isff = ATH_FF_MAGIC_PRESENT(skb);
-@@ -603,109 +603,56 @@
- 				need_tailroom += cip->ic_miclen;
- 	}
- 
--	if (skb_shared(skb)) {
--		/* Take our own reference to the node in the clone */
--		ieee80211_ref_node(SKB_NI(skb));
--		/* Unshare the node, decrementing users in the old skb */
--		skb = skb_unshare(skb, GFP_ATOMIC);
-+	need_headroom -= skb_headroom(skb);
-+	if (isff)
-+		need_tailroom -= skb_tailroom(skb2);
-+	else
-+		need_tailroom -= skb_tailroom(skb);
-+
-+	if (need_headroom < 0)
-+		need_headroom = 0;
-+	if (need_tailroom < 0)
-+		need_tailroom = 0;
-+
-+	if (skb_cloned(skb) || (need_headroom > 0) ||
-+		(!isff && (need_tailroom > 0))) {
-+
-+		if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) {
-+			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
-+				"%s: cannot expand storage (tail)\n", __func__);
-+			goto error;
-+		}
- 	}
- 
- #ifdef ATH_SUPERG_FF
- 	if (isff) {
--		if (skb == NULL) {
--			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--				"%s: cannot unshare for encapsulation\n",
--				__func__);
--			vap->iv_stats.is_tx_nobuf++;
--			ieee80211_dev_kfree_skb(&skb2);
--
--			return NULL;
--		}
-+		inter_headroom -= skb_headroom(skb2);
-+		if (inter_headroom < 0)
-+			inter_headroom = 0;
-+		if ((skb_cloned(skb2) ||
-+			(inter_headroom > 0) || (need_tailroom > 0))) {
- 
--		/* first skb header */
--		if (skb_headroom(skb) < need_headroom) {
--			struct sk_buff *tmp = skb;
--			skb = skb_realloc_headroom(skb, need_headroom);
--			if (skb == NULL) {
-+			if (pskb_expand_head(skb2, inter_headroom,
-+				need_tailroom, GFP_ATOMIC)) {
- 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--					"%s: cannot expand storage (head1)\n",
--					__func__);
--				vap->iv_stats.is_tx_nobuf++;
--				ieee80211_dev_kfree_skb(&skb2);
--				return NULL;
--			} else
--				ieee80211_skb_copy_noderef(tmp, skb);
--			ieee80211_dev_kfree_skb(&tmp);
--			/* NB: cb[] area was copied, but not next ptr. must do that
--			 *     prior to return on success. */
--		}
--
--		/* second skb with header and tail adjustments possible */
--		if (skb_tailroom(skb2) < need_tailroom) {
--			int n = 0;
--			if (inter_headroom > skb_headroom(skb2))
--				n = inter_headroom - skb_headroom(skb2);
--			if (pskb_expand_head(skb2, n,
--			    need_tailroom - skb_tailroom(skb2), GFP_ATOMIC)) {
--				ieee80211_dev_kfree_skb(&skb2);
--				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--					"%s: cannot expand storage (tail2)\n",
--					__func__);
--				vap->iv_stats.is_tx_nobuf++;
--				/* this shouldn't happen, but don't send first ff either */
--				ieee80211_dev_kfree_skb(&skb);
-+					"%s: cannot expand storage (tail)\n", __func__);
-+				goto error;
- 			}
--		} else if (skb_headroom(skb2) < inter_headroom) {
--			struct sk_buff *tmp = skb2;
--
--			skb2 = skb_realloc_headroom(skb2, inter_headroom);
--			if (skb2 == NULL) {
--				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--					"%s: cannot expand storage (head2)\n",
--					__func__);
--				vap->iv_stats.is_tx_nobuf++;
--				/* this shouldn't happen, but don't send first ff either */
--				ieee80211_dev_kfree_skb(&skb);
--				skb = NULL;
--			} else
--				ieee80211_skb_copy_noderef(tmp, skb);
--			ieee80211_dev_kfree_skb(&tmp);
- 		}
--		if (skb) {
--			skb->next = skb2;
--		}
--		return skb;
-+		skb->next = skb2;
- 	}
- #endif /* ATH_SUPERG_FF */
--	if (skb == NULL) {
--		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--			"%s: cannot unshare for encapsulation\n", __func__);
--		vap->iv_stats.is_tx_nobuf++;
--	} else if (skb_tailroom(skb) < need_tailroom) {
--		int n = 0;
--		if (need_headroom > skb_headroom(skb))
--			n = need_headroom - skb_headroom(skb);
--		if (pskb_expand_head(skb, n, need_tailroom - 
--					skb_tailroom(skb), GFP_ATOMIC)) {
--			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--				"%s: cannot expand storage (tail)\n", __func__);
--			vap->iv_stats.is_tx_nobuf++;
--			ieee80211_dev_kfree_skb(&skb);
--		}
--	} else if (skb_headroom(skb) < need_headroom) {
--		struct sk_buff *tmp = skb;
--		skb = skb_realloc_headroom(skb, need_headroom);
--		/* Increment reference count after copy */
--		if (skb == NULL) {
--			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
--				"%s: cannot expand storage (head)\n", __func__);
--			vap->iv_stats.is_tx_nobuf++;
--		} else
--			ieee80211_skb_copy_noderef(tmp, skb);
--		ieee80211_dev_kfree_skb(&tmp);
--	}
- 
- 	return skb;
-+
-+error:
-+	vap->iv_stats.is_tx_nobuf++;
-+	ieee80211_dev_kfree_skb(&skb);
-+#ifdef ATH_SUPERG_FF
-+	if (skb2)
-+		ieee80211_dev_kfree_skb(&skb2);
-+#endif
-+	return NULL;
- }
- 
- #define	KEY_UNDEFINED(k)	((k).wk_cipher == &ieee80211_cipher_none)
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -713,7 +713,7 @@
- 			/* ether_type must be length as FF frames are always LLC/SNAP encap'd */ 
- 			frame_len = ntohs(eh_tmp->ether_type); 
- 
--			skb1 = skb_copy(skb, GFP_ATOMIC);
-+			skb1 = skb_clone(skb, GFP_ATOMIC);
- 			if (skb1 == NULL)
- 				goto err;
- 			ieee80211_skb_copy_noderef(skb, skb1);
-@@ -1118,7 +1118,7 @@
- 
- 		if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
- 			/* Create a SKB for the BSS to send out. */
--			skb1 = skb_copy(skb, GFP_ATOMIC);
-+			skb1 = skb_clone(skb, GFP_ATOMIC);
- 			if (skb1)
- 				SKB_NI(skb1) = ieee80211_ref_node(vap->iv_bss); 
- 		}
-@@ -2265,7 +2265,7 @@
- 	if (filter_type && ((vap->app_filter & filter_type) == filter_type)) {
- 		struct sk_buff *skb1;
- 
--		skb1 = skb_copy(skb, GFP_ATOMIC);
-+		skb1 = skb_clone(skb, GFP_ATOMIC);
- 		if (skb1 == NULL)
- 			return;
- 		/* We duplicate the reference after skb_copy */
diff --git a/package/madwifi/patches-r3776/310-minstrel_sampling.patch b/package/madwifi/patches-r3776/310-minstrel_sampling.patch
deleted file mode 100644
index b7f55d500..000000000
--- a/package/madwifi/patches-r3776/310-minstrel_sampling.patch
+++ /dev/null
@@ -1,84 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8110,6 +8110,7 @@
- 		ath_hal_setupxtxdesc(sc->sc_ah, ds, mrr.rate1, mrr.retries1,
- 				     mrr.rate2, mrr.retries2,
- 				     mrr.rate3, mrr.retries3);
-+		bf->rcflags = mrr.privflags;
- 	}
- 
- #ifndef ATH_SUPERG_FF
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -454,6 +454,7 @@
- 	u_int16_t bf_flags;				/* tx descriptor flags */
- 	u_int64_t bf_tsf;
- 	int16_t bf_channoise;
-+	unsigned int rcflags;
- #ifdef ATH_SUPERG_FF
- 	/* XXX: combine this with bf_skbaddr if it ever changes to accommodate
- 	 *      multiple segments.
---- a/ath_rate/minstrel/minstrel.c
-+++ b/ath_rate/minstrel/minstrel.c
-@@ -341,18 +341,21 @@
- 		if (sn->static_rate_ndx >= 0) {
- 			    ndx = sn->static_rate_ndx;
- 		} else {
-+			int delta;
-+
- 			sn->packet_count++;
- 			sn->random_n = (sn->a * sn->random_n) + sn->b;
- 			offset = sn->random_n & 0xf;
- 
--			if ((((100 * sn->sample_count) / sn->packet_count) < 
--					 ath_lookaround_rate) && 
--					(offset < 2)) {
-+			delta = (sn->packet_count * ath_lookaround_rate / 100) - sn->sample_count;
-+			if ((delta > 0) && (offset < 2)) {
- 				sn->sample_count++;
- 				sn->is_sampling = 1;
- 				if (sn->packet_count >= 10000) {
- 					sn->sample_count = 0;
- 					sn->packet_count = 0;
-+				} else if (delta > sn->num_rates * 2) {
-+					sn->sample_count += ((delta - sn->num_rates * 2) * ath_lookaround_rate) / 100;
- 				}
- 
- 				/* Don't look for slowest rate (i.e. slowest
-@@ -420,11 +423,14 @@
- 		if (sn->num_rates <= 0)
- 			return;
- 
-+		mrr->privflags = sn->is_sampling;
- 		if (sn->is_sampling) {
- 			sn->is_sampling = 0;
--			if (sn->rs_sample_rate_slower)
-+			if (sn->rs_sample_rate_slower) {
- 				rc1 = sn->rs_sample_rate;
--			else
-+				if (sn->sample_count > 0)
-+					sn->sample_count--;
-+			} else
- 				rc1 = sn->max_tp_rate;
- 		} else {
- 			rc1 = sn->max_tp_rate2;
-@@ -552,6 +558,9 @@
- 		if (tries <= tries1)
- 			return;
- 
-+		if (bf->rcflags)
-+			sn->sample_count++;
-+
- 		if  (tries2 < 0)
- 			return;
- 		tries = tries - tries1;
---- a/net80211/ieee80211_rate.h
-+++ b/net80211/ieee80211_rate.h
-@@ -87,6 +87,7 @@
- 	int retries2;
- 	int rate3;
- 	int retries3;
-+	int privflags;
- };
- 
- struct ieee80211_rate_ops {
diff --git a/package/madwifi/patches-r3776/311-protmode_trigger.patch b/package/madwifi/patches-r3776/311-protmode_trigger.patch
deleted file mode 100644
index 2f462b9a6..000000000
--- a/package/madwifi/patches-r3776/311-protmode_trigger.patch
+++ /dev/null
@@ -1,135 +0,0 @@
---- a/net80211/ieee80211.c
-+++ b/net80211/ieee80211.c
-@@ -347,7 +347,9 @@
- 			IEEE80211_MS_TO_TU(IEEE80211_BMISSTHRESH_DEFAULT_MS), 
- 			ic->ic_lintval), ic->ic_lintval);
- 	}
--		
-+	ic->ic_protmode_timeout = IEEE80211_PROTMODE_TIMEOUT;
-+	ic->ic_protmode_rssi = IEEE80211_PROTMODE_RSSITHR;
-+
- 	IEEE80211_LOCK_INIT(ic, "ieee80211com");
- 	IEEE80211_VAPS_LOCK_INIT(ic, "ieee80211com_vaps");
- 	TAILQ_INIT(&ic->ic_vaps);
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -3382,14 +3382,18 @@
- 			IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
- 
- 			/* Assume no ERP IE == 11b AP */
--			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
--				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
-+			if ((!has_erp || (has_erp &&
-+				(scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
-+				(rssi > ic->ic_protmode_rssi)) {
- 				struct ieee80211vap *tmpvap;
- 
--				ic->ic_flags |= IEEE80211_F_USEPROT;
--				TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
--					tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+				if (!(ic->ic_flags & IEEE80211_F_USEPROT)) {
-+					ic->ic_flags |= IEEE80211_F_USEPROT;
-+					TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
-+						tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+					}
- 				}
-+				ic->ic_protmode_lasttrig = jiffies;
- 			}
- 		}
- 
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -652,6 +652,8 @@
- 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
- 	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
- 	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
-+	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
-+	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
- };
- 
- #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -138,6 +138,9 @@
- 
- #define	IEEE80211_APPIE_MAX	1024
- 
-+#define IEEE80211_PROTMODE_RSSITHR	15	/* default rssi threshold for protection mode trigger */
-+#define IEEE80211_PROTMODE_TIMEOUT	30	/* timeout for keeping protection mode alive */
-+
- #define IEEE80211_PWRCONSTRAINT_VAL(ic) \
- 	(((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \
- 	    (ic)->ic_bsschan->ic_maxregpower - (ic)->ic_curchanmaxpwr : 0)
-@@ -335,6 +338,9 @@
- 	u_int16_t ic_newtxpowlimit; 		/* tx power limit to change to (in 0.5 dBm) */
- 	u_int16_t ic_uapsdmaxtriggers; 		/* max triggers that could arrive */
- 	u_int8_t ic_coverageclass; 		/* coverage class */
-+	u_int8_t ic_protmode_rssi;			/* rssi threshold for protection mode */
-+	u_int64_t ic_protmode_lasttrig;		/* last trigger for protection mode */
-+	u_int16_t ic_protmode_timeout;		/* protection mode timeout */
- 
- 	/* Channel state:
- 	 *
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -2336,6 +2336,12 @@
- 	case IEEE80211_PARAM_RSSI_EWMA:
- 		ic->ic_rssi_ewma = value;
- 		break;
-+	case IEEE80211_PARAM_PROTMODE_TIMEOUT:
-+		ic->ic_protmode_timeout = value;
-+		break;
-+	case IEEE80211_PARAM_PROTMODE_RSSI:
-+		ic->ic_protmode_rssi = value;
-+		break;
- 	case IEEE80211_PARAM_MCASTCIPHER:
- 		if ((vap->iv_caps & cipher2cap(value)) == 0 &&
- 		    !ieee80211_crypto_available(vap, value))
-@@ -2992,6 +2998,12 @@
- 	case IEEE80211_PARAM_RSSI_EWMA:
- 		param[0] = ic->ic_rssi_ewma;
- 		break;
-+	case IEEE80211_PARAM_PROTMODE_TIMEOUT:
-+		param[0] = ic->ic_protmode_timeout;
-+		break;
-+	case IEEE80211_PARAM_PROTMODE_RSSI:
-+		param[0] = ic->ic_protmode_rssi;
-+		break;
- 	case IEEE80211_PARAM_MCASTCIPHER:
- 		param[0] = rsn->rsn_mcastcipher;
- 		break;
-@@ -5384,6 +5396,14 @@
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protmode" },
- 	{ IEEE80211_PARAM_PROTMODE,
- 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protmode" },
-+	{ IEEE80211_PARAM_PROTMODE_RSSI,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protrssi" },
-+	{ IEEE80211_PARAM_PROTMODE_RSSI,
-+	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protrssi" },
-+	{ IEEE80211_PARAM_PROTMODE_TIMEOUT,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prottime" },
-+	{ IEEE80211_PARAM_PROTMODE_TIMEOUT,
-+	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_prottime" },
- 	{ IEEE80211_PARAM_MCASTCIPHER,
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcastcipher" },
- 	{ IEEE80211_PARAM_MCASTCIPHER,
---- a/net80211/ieee80211_node.c
-+++ b/net80211/ieee80211_node.c
-@@ -1591,6 +1591,17 @@
- 
- 	ieee80211_scan_timeout(ic);
- 	ieee80211_timeout_stations(&ic->ic_sta);
-+	if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
-+		(ic->ic_protmode_lasttrig + ic->ic_protmode_timeout * HZ <
-+			jiffies)) {
-+		struct ieee80211vap *tmpvap;
-+
-+		/* expire protection mode */
-+		ic->ic_flags &= ~IEEE80211_F_USEPROT;
-+		TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
-+			tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
-+		}
-+	}
- 
- 	mod_timer(&ic->ic_inact, jiffies + IEEE80211_INACT_WAIT * HZ);
- }
diff --git a/package/madwifi/patches-r3776/312-ack_cts_rate.patch b/package/madwifi/patches-r3776/312-ack_cts_rate.patch
deleted file mode 100644
index 42bb4c171..000000000
--- a/package/madwifi/patches-r3776/312-ack_cts_rate.patch
+++ /dev/null
@@ -1,40 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -10890,8 +10890,13 @@
- 				break;
- #endif
- 			case ATH_ACKRATE:
--				sc->sc_ackrate = val;
--				ath_set_ack_bitrate(sc, sc->sc_ackrate);
-+				if (val == -1)
-+					sc->sc_ackrate_override = 0;
-+				else {
-+					sc->sc_ackrate_override = 1;
-+					sc->sc_ackrate = val;
-+					ath_set_ack_bitrate(sc, sc->sc_ackrate);
-+				}
- 				break;
- 			case ATH_RP:
- 				ath_rp_record(sc,
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -698,6 +698,7 @@
- 	unsigned int	sc_hasclrkey:1;		/* CLR key supported */
- 	unsigned int	sc_stagbeacons:1;	/* use staggered beacons */
- 	unsigned int	sc_dfswait:1;		/* waiting on channel for radar detect */
-+	unsigned int	sc_ackrate_override:1;	/* override ack rate */
- 	unsigned int	sc_ackrate:1;		/* send acks at high bitrate */
- 	unsigned int	sc_dfs_cac:1;		/* waiting on channel for radar detect */
- 	unsigned int	sc_hasintmit:1;		/* Interference mitigation */
---- a/ath/if_ath_hal_extensions.c
-+++ b/ath/if_ath_hal_extensions.c
-@@ -129,6 +129,9 @@
- int
- ath_set_ack_bitrate(struct ath_softc *sc, int high)
- {
-+	if (!sc->sc_ackrate_override)
-+		return 0;
-+
- 	if (ar_device(sc->devid) == 5212 || ar_device(sc->devid) == 5213) {
- 		/* set ack to be sent at low bit-rate */
- 		u_int32_t v = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
diff --git a/package/madwifi/patches-r3776/313-reset_channelchange.patch b/package/madwifi/patches-r3776/313-reset_channelchange.patch
deleted file mode 100644
index 42d18ece0..000000000
--- a/package/madwifi/patches-r3776/313-reset_channelchange.patch
+++ /dev/null
@@ -1,18 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8866,14 +8866,7 @@
- 			hchan.channel,
- 			jiffies);
- 
--		/* ath_hal_reset with chanchange = AH_TRUE doesn't seem to
--		 * completely reset the state of the card.  According to
--		 * reports from ticket #1106, kismet and aircrack people they
--		 * needed to do the reset with chanchange = AH_FALSE in order
--		 * to receive traffic when peforming high velocity channel
--		 * changes. */
--		if (!ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_TRUE, &status)   ||
--		    !ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_FALSE, &status)) {
-+		if (!ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_TRUE, &status)) {
- 			EPRINTF(sc, "Unable to reset channel %u (%u MHz) "
- 				"flags 0x%x '%s' (HAL status %u)\n",
- 				ieee80211_chan2ieee(ic, chan), chan->ic_freq,
diff --git a/package/madwifi/patches-r3776/314-wisoc_softled.patch b/package/madwifi/patches-r3776/314-wisoc_softled.patch
deleted file mode 100644
index ca5ffdce4..000000000
--- a/package/madwifi/patches-r3776/314-wisoc_softled.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/ath/if_ath_ahb.c
-+++ b/ath/if_ath_ahb.c
-@@ -245,6 +245,8 @@
- 	num_activesc++;
- 	/* Ready to process interrupts */
- 
-+	sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */
-+	sc->aps_sc.sc_ledpin = config->board->sysLedGpio;
- 	sc->aps_sc.sc_invalid = 0;
- 	return 0;
- 
diff --git a/package/madwifi/patches-r3776/315-scanlist.patch b/package/madwifi/patches-r3776/315-scanlist.patch
deleted file mode 100644
index 0ae0ed010..000000000
--- a/package/madwifi/patches-r3776/315-scanlist.patch
+++ /dev/null
@@ -1,876 +0,0 @@
---- a/net80211/ieee80211_scan_sta.c
-+++ b/net80211/ieee80211_scan_sta.c
-@@ -318,147 +318,6 @@
- #undef ISPROBE
- }
- 
--static struct ieee80211_channel *
--find11gchannel(struct ieee80211com *ic, int i, int freq)
--{
--	struct ieee80211_channel *c;
--	int j;
--
--	/*
--	 * The normal ordering in the channel list is b channel
--	 * immediately followed by g so optimize the search for
--	 * this.  We'll still do a full search just in case.
--	 */
--	for (j = i+1; j < ic->ic_nchans; j++) {
--		c = &ic->ic_channels[j];
--		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
--			return c;
--	}
--	for (j = 0; j < i; j++) {
--		c = &ic->ic_channels[j];
--		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
--			return c;
--	}
--	return NULL;
--}
--static const u_int chanflags[] = {
--	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
--	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
--	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
--	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
--	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
--	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
--	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
--	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
--};
--
--static void
--add_channels(struct ieee80211com *ic,
--	struct ieee80211_scan_state *ss,
--	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
--{
--	struct ieee80211_channel *c, *cg;
--	u_int modeflags;
--	int i;
--
--	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
--	modeflags = chanflags[mode];
--	for (i = 0; i < nfreq; i++) {
--		c = ieee80211_find_channel(ic, freq[i], modeflags);
--		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
--			continue;
--		if (mode == IEEE80211_MODE_AUTO) {
--			/*
--			 * XXX special-case 11b/g channels so we select
--			 *     the g channel if both are present.
--			 */
--			if (IEEE80211_IS_CHAN_B(c) &&
--			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
--				c = cg;
--		}
--		if (ss->ss_last >= IEEE80211_SCAN_MAX)
--			break;
--		ss->ss_chans[ss->ss_last++] = c;
--	}
--}
--
--static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */
--{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
--static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
--{ 5170, 5190, 5210, 5230 };
--static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
--{ 2412, 2437, 2462, 2442, 2472 };
--static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
--{ 5745, 5765, 5785, 5805, 5825 };
--static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */
--{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
--static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
--{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
--static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
--{ 2484 };
--static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
--{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
--static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
--{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
--#ifdef ATH_TURBO_SCAN
--static const u_int16_t rcl5[] =		/* 3 static turbo channels */
--{ 5210, 5250, 5290 };
--static const u_int16_t rcl6[] =		/* 2 static turbo channels */
--{ 5760, 5800 };
--static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
--{ 5540, 5580, 5620, 5660 };
--static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
--{ 2437 };
--static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
--{ 5200, 5240, 5280, 5765, 5805 };
--#endif /* ATH_TURBO_SCAN */
--
--struct scanlist {
--	u_int16_t	mode;
--	u_int16_t	count;
--	const u_int16_t	*list;
--};
--
--#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
--#define	X(a)	.count = sizeof(a)/sizeof(a[0]), .list = a
--
--static const struct scanlist staScanTable[] = {
--	{ IEEE80211_MODE_11B,   		X(rcl3) },
--	{ IEEE80211_MODE_11A,   		X(rcl1) },
--	{ IEEE80211_MODE_11A,   		X(rcl2) },
--	{ IEEE80211_MODE_11B,   		X(rcl8) },
--	{ IEEE80211_MODE_11B,   		X(rcl9) },
--	{ IEEE80211_MODE_11A,   		X(rcl4) },
--#ifdef ATH_TURBO_SCAN
--	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5) },
--	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6) },
--	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
--	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
--#endif /* ATH_TURBO_SCAN */
--	{ IEEE80211_MODE_11A,			X(rcl7) },
--	{ IEEE80211_MODE_11B,			X(rcl10) },
--	{ IEEE80211_MODE_11A,			X(rcl11) },
--#ifdef ATH_TURBO_SCAN
--	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
--#endif /* ATH_TURBO_SCAN */
--	{ .list = NULL }
--};
--
--#undef X
--
--static int
--checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
--{
--	int i;
--
--	for (; scan->list != NULL; scan++) {
--		for (i = 0; i < scan->count; i++)
--			if (scan->list[i] == c->ic_freq)
--				return 1;
--	}
--	return 0;
--}
--
- /*
-  * Start a station-mode scan by populating the channel list.
-  */
-@@ -467,81 +326,11 @@
- {
- 	struct ieee80211com *ic = vap->iv_ic;
- 	struct sta_table *st = ss->ss_priv;
--	const struct scanlist *scan;
--	enum ieee80211_phymode mode;
--	struct ieee80211_channel *c;
--	int i;
- 
- 	ss->ss_last = 0;
--	/*
--	 * Use the table of ordered channels to construct the list
--	 * of channels for scanning.  Any channels in the ordered
--	 * list not in the master list will be discarded.
--	 */
--	for (scan = staScanTable; scan->list != NULL; scan++) {
--		mode = scan->mode;
--		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
--			/*
--			 * If a desired mode was specified, scan only 
--			 * channels that satisfy that constraint.
--			 */
--			if (vap->iv_des_mode != mode) {
--				/*
--				 * The scan table marks 2.4Ghz channels as b
--				 * so if the desired mode is 11g, then use
--				 * the 11b channel list but upgrade the mode.
--				 */
--				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
--				    mode != IEEE80211_MODE_11B)
--					continue;
--				mode = IEEE80211_MODE_11G;	/* upgrade */
--			}
--		} else {
--			/*
--			 * This lets ieee80211_scan_add_channels
--			 * upgrade an 11b channel to 11g if available.
--			 */
--			if (mode == IEEE80211_MODE_11B)
--				mode = IEEE80211_MODE_AUTO;
--		}
--		/* XR does not operate on turbo channels */
--		if ((vap->iv_flags & IEEE80211_F_XR) &&
--		    (mode == IEEE80211_MODE_TURBO_A ||
--		     mode == IEEE80211_MODE_TURBO_G))
--			continue;
--		/*
--		 * Add the list of the channels; any that are not
--		 * in the master channel list will be discarded.
--		 */
--		add_channels(ic, ss, mode, scan->list, scan->count);
--	}
--
--	/*
--	 * Add the channels from the ic (from HAL) that are not present
--	 * in the staScanTable.
--	 */
--	for (i = 0; i < ic->ic_nchans; i++) {
--		c = &ic->ic_channels[i];
--		/*
--		 * scan dynamic turbo channels in normal mode.
--		 */
--		if (IEEE80211_IS_CHAN_DTURBO(c))
--			continue;
--		mode = ieee80211_chan2mode(c);
--		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
--			/*
--			 * If a desired mode was specified, scan only 
--			 * channels that satisfy that constraint.
--			 */
--			if (vap->iv_des_mode != mode)
--				continue;
--
--		}
--		if (!checktable(staScanTable, c))
--			ss->ss_chans[ss->ss_last++] = c;
--	}
--
-+	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
- 	ss->ss_next = 0;
-+
- 	/* XXX tunables */
- 	/* 
- 	 * The scanner will stay on station for ss_maxdwell ms (using a 
-@@ -750,17 +539,7 @@
- 	fail = 0;
- 	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan)))
- 		fail |= 0x01;
--	/*
--	 * NB: normally the desired mode is used to construct
--	 * the channel list, but it's possible for the scan
--	 * cache to include entries for stations outside this
--	 * list so we check the desired mode here to weed them
--	 * out.
--	 */
--	if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&
--	    (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
--	    chanflags[vap->iv_des_mode])
--		fail |= 0x01;
-+
- 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
- 		if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
- 			fail |= 0x02;
-@@ -1175,78 +954,6 @@
- 	.scan_default		= ieee80211_sta_join,
- };
- 
--/*
-- * Start an adhoc-mode scan by populating the channel list.
-- */
--static int
--adhoc_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
--{
--	struct ieee80211com *ic = vap->iv_ic;
--	struct sta_table *st = ss->ss_priv;
--	const struct scanlist *scan;
--	enum ieee80211_phymode mode;
--
--	ss->ss_last = 0;
--	/*
--	 * Use the table of ordered channels to construct the list
--	 * of channels for scanning.  Any channels in the ordered
--	 * list not in the master list will be discarded.
--	 */
--	for (scan = staScanTable; scan->list != NULL; scan++) {
--		mode = scan->mode;
--		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
--			/*
--			 * If a desired mode was specified, scan only 
--			 * channels that satisfy that constraint.
--			 */
--			if (vap->iv_des_mode != mode) {
--				/*
--				 * The scan table marks 2.4Ghz channels as b
--				 * so if the desired mode is 11g, then use
--				 * the 11b channel list but upgrade the mode.
--				 */
--				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
--				    mode != IEEE80211_MODE_11B)
--					continue;
--				mode = IEEE80211_MODE_11G;	/* upgrade */
--			}
--		} else {
--			/*
--			 * This lets ieee80211_scan_add_channels
--			 * upgrade an 11b channel to 11g if available.
--			 */
--			if (mode == IEEE80211_MODE_11B)
--				mode = IEEE80211_MODE_AUTO;
--		}
--		/* XR does not operate on turbo channels */
--		if ((vap->iv_flags & IEEE80211_F_XR) &&
--		    (mode == IEEE80211_MODE_TURBO_A ||
--		     mode == IEEE80211_MODE_TURBO_G))
--			continue;
--		/*
--		 * Add the list of the channels; any that are not
--		 * in the master channel list will be discarded.
--		 */
--		add_channels(ic, ss, mode, scan->list, scan->count);
--	}
--	ss->ss_next = 0;
--	/* XXX tunables */
--	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
--	ss->ss_maxdwell = msecs_to_jiffies(200);	/* 200ms */
--
--#ifdef IEEE80211_DEBUG
--	if (ieee80211_msg_scan(vap)) {
--		printk("%s: scan set ", vap->iv_dev->name);
--		ieee80211_scan_dump_channels(ss);
--		printk(" dwell min %ld max %ld\n",
--			ss->ss_mindwell, ss->ss_maxdwell);
--	}
--#endif /* IEEE80211_DEBUG */
--
--	st->st_newscan = 1;
--
--	return 0;
--}
- 
- /*
-  * Select a channel to start an adhoc network on.
-@@ -1412,7 +1119,7 @@
- 	.scan_name		= "default",
- 	.scan_attach		= sta_attach,
- 	.scan_detach		= sta_detach,
--	.scan_start		= adhoc_start,
-+	.scan_start		= sta_start,
- 	.scan_restart		= sta_restart,
- 	.scan_cancel		= sta_cancel,
- 	.scan_end		= adhoc_pick_bss,
---- a/net80211/ieee80211.c
-+++ b/net80211/ieee80211.c
-@@ -292,6 +292,11 @@
- 			("channel with bogus ieee number %u", c->ic_ieee));
- 		setbit(ic->ic_chan_avail, c->ic_ieee);
- 
-+		if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
-+			c->ic_scanflags |= IEEE80211_NOSCAN_SET;
-+		else
-+			c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
-+
- 		/* Identify mode capabilities. */
- 		if (IEEE80211_IS_CHAN_A(c))
- 			ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
---- a/net80211/_ieee80211.h
-+++ b/net80211/_ieee80211.h
-@@ -132,6 +132,11 @@
- 	IEEE80211_SCAN_FIRST	= 2,	/* take first suitable candidate */
- };
- 
-+enum ieee80211_scanflags {
-+	IEEE80211_NOSCAN_DEFAULT = (1 << 0),
-+	IEEE80211_NOSCAN_SET     = (1 << 1),
-+};
-+
- /*
-  * Channels are specified by frequency and attributes.
-  */
-@@ -142,6 +147,7 @@
- 	int8_t ic_maxregpower;	/* maximum regulatory tx power in dBm */
- 	int8_t ic_maxpower;	/* maximum tx power in dBm */
- 	int8_t ic_minpower;	/* minimum tx power in dBm */
-+	u_int8_t ic_scanflags;
- };
- 
- #define	IEEE80211_CHAN_MAX	255
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -556,6 +556,7 @@
- #define	IEEE80211_IOCTL_WDSADDMAC	(SIOCIWFIRSTPRIV+26)
- #define	IEEE80211_IOCTL_WDSDELMAC	(SIOCIWFIRSTPRIV+28)
- #define	IEEE80211_IOCTL_KICKMAC		(SIOCIWFIRSTPRIV+30)
-+#define	IEEE80211_IOCTL_SETSCANLIST	(SIOCIWFIRSTPRIV+31)
- 
- enum {
- 	IEEE80211_WMMPARAMS_CWMIN       = 1,
---- a/net80211/ieee80211_scan_ap.c
-+++ b/net80211/ieee80211_scan_ap.c
-@@ -200,131 +200,7 @@
- 
- static int ap_flush(struct ieee80211_scan_state *);
- static void action_tasklet(IEEE80211_TQUEUE_ARG);
--static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, 
--		int i, int freq);
- 
--static const u_int chanflags[] = {
--	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
--	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
--	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
--	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
--	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
--	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode 
--							      * look for AP in 
--							      * normal channel 
--							      */
--	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
--	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
--};
--
--static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 
--					 *                36, 40, 44, 48 */
--{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
--static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
--{ 5170, 5190, 5210, 5230 };
--static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
--{ 2412, 2437, 2462, 2442, 2472 };
--static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
--{ 5745, 5765, 5785, 5805, 5825 };
--static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100, 104, 108, 112,
--					 *                  116, 120, 124, 128, 
--					 *                  132, 136, 140 */
--{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
--static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
--{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
--static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
--{ 2484 };
--static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
--{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
--static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
--{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
--#ifdef ATH_TURBO_SCAN
--static const u_int16_t rcl5[] =		/* 3 static turbo channels */
--{ 5210, 5250, 5290 };
--static const u_int16_t rcl6[] =		/* 2 static turbo channels */
--{ 5760, 5800 };
--static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
--{ 5540, 5580, 5620, 5660 };
--static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
--{ 2437 };
--static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
--{ 5200, 5240, 5280, 5765, 5805 };
--#endif /* ATH_TURBO_SCAN */
--
--struct scanlist {
--	u_int16_t	mode;
--	u_int16_t	count;
--	const u_int16_t	*list;
--};
--
--#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
--#define	X(a)	.count = ARRAY_SIZE(a), .list = a
--
--static const struct scanlist staScanTable[] = {
--	{ IEEE80211_MODE_11B,   		X(rcl3)  },
--	{ IEEE80211_MODE_11A,   		X(rcl1)  },
--	{ IEEE80211_MODE_11A,   		X(rcl2)  },
--	{ IEEE80211_MODE_11B,   		X(rcl8)  },
--	{ IEEE80211_MODE_11B,   		X(rcl9)  },
--	{ IEEE80211_MODE_11A,   		X(rcl4)  },
--#ifdef ATH_TURBO_SCAN
--	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5)  },
--	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6)  },
--	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
--	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
--#endif /* ATH_TURBO_SCAN */
--	{ IEEE80211_MODE_11A,			X(rcl7)  },
--	{ IEEE80211_MODE_11B,			X(rcl10) },
--	{ IEEE80211_MODE_11A,			X(rcl11) },
--#ifdef ATH_TURBO_SCAN
--	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
--#endif /* ATH_TURBO_SCAN */
--	{ .list = NULL }
--};
--
--#undef X
--/* This function must be invoked with locks acquired */
--static void
--add_channels(struct ieee80211com *ic,
--	struct ieee80211_scan_state *ss,
--	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
--{
--	struct ieee80211_channel *c, *cg;
--	u_int modeflags;
--	int i;
--
--	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
--	modeflags = chanflags[mode];
--	for (i = 0; i < nfreq; i++) {
--		c = ieee80211_find_channel(ic, freq[i], modeflags);
--		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
--			continue;
--		if (mode == IEEE80211_MODE_AUTO) {
--			/* XXX special-case 11b/g channels so we select
--			 *     the g channel if both are present. */
--			if (IEEE80211_IS_CHAN_B(c) &&
--			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
--				c = cg;
--		}
--		if (ss->ss_last >= IEEE80211_SCAN_MAX)
--			break;
--		ss->ss_chans[ss->ss_last++] = c;
--	}
--}
--
--/* This function must be invoked with locks acquired */
--static int
--checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
--{
--	int i;
--
--	for (; scan->list != NULL; scan++) {
--		for (i = 0; i < scan->count; i++)
--			if (scan->list[i] == c->ic_freq)
--				return 1;
--	}
--	return 0;
--}
- 
- /*
-  * Attach prior to any scanning work.
-@@ -398,29 +274,6 @@
- 		ieee80211_saveie(iep, ie);
- }
- 
--/* This function must be invoked with locks acquired */
--static struct ieee80211_channel *
--find11gchannel(struct ieee80211com *ic, int i, int freq)
--{
--	struct ieee80211_channel *c;
--	int j;
--
--	/* The normal ordering in the channel list is b channel
--	 * immediately followed by g so optimize the search for
--	 * this.  We'll still do a full search just in case. */
--	for (j = i + 1; j < ic->ic_nchans; j++) {
--		c = &ic->ic_channels[j];
--		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
--			return c;
--	}
--	for (j = 0; j < i; j++) {
--		c = &ic->ic_channels[j];
--		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
--			return c;
--	}
--	return NULL;
--}
--
- /*
-  * Start an ap scan by populating the channel list.
-  */
-@@ -429,90 +282,14 @@
- {
- 	struct ap_state *as 	    = ss->ss_priv;
- 	struct ieee80211com *ic     = NULL;
--	const struct scanlist *sl   = NULL;
--	struct ieee80211_channel *c = NULL;
--	int i;
--	unsigned int mode = 0;
- 
- 	SCAN_AP_LOCK_IRQ(as);
- 	ic = vap->iv_ic;
- 	/* Determine mode flags to match, or leave zero for auto mode */
- 	as->as_vap_desired_mode = vap->iv_des_mode;
- 	as->as_required_mode    = 0;
--	if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) {
--		as->as_required_mode = chanflags[as->as_vap_desired_mode];
--		if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && 
--		    (as->as_required_mode != IEEE80211_CHAN_ST)) {
--			/* Fixup for dynamic turbo flags */
--			if (as->as_vap_desired_mode == IEEE80211_MODE_11G)
--				as->as_required_mode = IEEE80211_CHAN_108G;
--			else
--				as->as_required_mode = IEEE80211_CHAN_108A;
--		}
--	}
--
--	ss->ss_last = 0;
--	/* Use the table of ordered channels to construct the list
--	 * of channels for scanning.  Any channels in the ordered
--	 * list not in the master list will be discarded. */
--	for (sl = staScanTable; sl->list != NULL; sl++) {
--		mode = sl->mode;
--
--		/* The scan table marks 2.4Ghz channels as b
--		 * so if the desired mode is 11g, then use
--		 * the 11b channel list but upgrade the mode. */
--		if (as->as_vap_desired_mode &&
--		    (as->as_vap_desired_mode != mode) && 
--		    (as->as_vap_desired_mode == IEEE80211_MODE_11G) && 
--		    (mode == IEEE80211_MODE_11B))
--			mode = IEEE80211_MODE_11G;
--
--		/* If we are in "AUTO" mode, upgrade the mode to auto. 
--		 * This lets add_channels upgrade an 11b channel to 
--		 * 11g if available. */
--		if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B))
--			mode = IEEE80211_MODE_AUTO;
--
--		/* Add the list of the channels; any that are not
--		 * in the master channel list will be discarded. */
--		add_channels(ic, ss, mode, sl->list, sl->count);
--	}
--
--	/* Add the channels from the ic (from HAL) that are not present
--	 * in the staScanTable, assuming they pass the sanity checks... */
--	for (i = 0; i < ic->ic_nchans; i++) {
--		c = &ic->ic_channels[i];
--
--		/* XR is not supported on turbo channels */
--		if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR)
--			continue;
-+	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
- 
--		/* Dynamic channels are scanned in base mode */
--		if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c))
--			continue;
--
--		/* Use any 11g channel instead of 11b one. */
--		if (vap->iv_des_mode == IEEE80211_MODE_AUTO && 
--		    IEEE80211_IS_CHAN_B(c) &&
--		    find11gchannel(ic, i, c->ic_freq))
--			continue;
--
--		/* Do not add channels already put into the scan list by the
--		 * scan table - these have already been filtered by mode
--		 * and for whether they are in the active channel list. */
--		if (checktable(staScanTable, c))
--			continue;
--
--		/* Make sure the channel is active */
--		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
--			continue;
--
--		/* Don't overrun */
--		if (ss->ss_last >= IEEE80211_SCAN_MAX)
--			break;
--
--		ss->ss_chans[ss->ss_last++] = c;
--	}
- 	ss->ss_next = 0;
- 	/* XXX tunables */
- 	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
-@@ -831,13 +608,6 @@
- 		if (IEEE80211_IS_CHAN_RADAR(c->chan))
- 			continue;
- 
--		/* Do not select 802.11a ST if mode is specified and is not 
--		 * 802.11a ST */
--		if (as->as_required_mode &&
--		    IEEE80211_IS_CHAN_STURBO(c->chan) &&
--		    (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A))
--			continue;
--
- 		/* Verify mode matches any fixed mode specified */
- 		if ((c->chan->ic_flags & as->as_required_mode) != 
- 				as->as_required_mode)
---- a/net80211/ieee80211_scan.c
-+++ b/net80211/ieee80211_scan.c
-@@ -969,6 +969,80 @@
- 	}
- }
- 
-+static const u_int chanflags[] = {
-+	0,	/* IEEE80211_MODE_AUTO */
-+	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
-+	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
-+	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
-+	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
-+	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
-+	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
-+	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
-+};
-+
-+static struct ieee80211_channel *
-+find11gchannel(struct ieee80211com *ic, int i, int freq)
-+{
-+	struct ieee80211_channel *c;
-+	int j;
-+
-+	/*
-+	 * The normal ordering in the channel list is b channel
-+	 * immediately followed by g so optimize the search for
-+	 * this.  We'll still do a full search just in case.
-+	 */
-+	for (j = i+1; j < ic->ic_nchans; j++) {
-+		c = &ic->ic_channels[j];
-+		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
-+			return c;
-+	}
-+	for (j = 0; j < i; j++) {
-+		c = &ic->ic_channels[j];
-+		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
-+			return c;
-+	}
-+	return NULL;
-+}
-+
-+
-+void
-+ieee80211_scan_add_channels(struct ieee80211com *ic,
-+	struct ieee80211_scan_state *ss,
-+	enum ieee80211_phymode mode)
-+{
-+	struct ieee80211_channel *c, *cg;
-+	u_int modeflags;
-+	int i;
-+
-+	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
-+	modeflags = chanflags[mode];
-+	for (i = 0; i < ic->ic_nchans; i++) {
-+		c = &ic->ic_channels[i];
-+		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
-+			continue;
-+		if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
-+			continue;
-+		if (modeflags &&
-+			((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
-+			 (modeflags & IEEE80211_CHAN_ALLTURBO)))
-+			continue;
-+		if (mode == IEEE80211_MODE_AUTO) {
-+			/*
-+			 * XXX special-case 11b/g channels so we select
-+			 *     the g channel if both are present.
-+			 */
-+			if (IEEE80211_IS_CHAN_B(c) &&
-+			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
-+				continue;
-+		}
-+		if (ss->ss_last >= IEEE80211_SCAN_MAX)
-+			break;
-+		ss->ss_chans[ss->ss_last++] = c;
-+	}
-+}
-+EXPORT_SYMBOL(ieee80211_scan_add_channels);
-+
-+
- /*
-  * Execute radar channel change. This is called when a radar/dfs
-  * signal is detected.  AP mode only.  Return 1 on success, 0 on
---- a/net80211/ieee80211_scan.h
-+++ b/net80211/ieee80211_scan.h
-@@ -219,4 +219,7 @@
- void ieee80211_scanner_unregister(enum ieee80211_opmode,
- 	const struct ieee80211_scanner *);
- void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
-+void ieee80211_scan_add_channels(struct ieee80211com *ic,
-+	struct ieee80211_scan_state *ss,
-+	enum ieee80211_phymode mode);
- #endif /* _NET80211_IEEE80211_SCAN_H_ */
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -3911,6 +3911,106 @@
- 	return ieee80211_ioctl_setmlme(dev, info, w, (char *)&mlme);
- }
- 
-+static inline void setflag(struct ieee80211_channel *c, int flag)
-+{
-+	if (flag)
-+		c->ic_scanflags |= IEEE80211_NOSCAN_SET;
-+	else
-+		c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
-+}
-+
-+static void setscanflag(struct ieee80211com *ic, int min, int max, int set)
-+{
-+	int i;
-+
-+	for (i = 0; i < ic->ic_nchans; i++) {
-+		struct ieee80211_channel *c = &ic->ic_channels[i];
-+
-+		if (min == -1) {
-+			if (!(c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT))
-+				setflag(c, set);
-+		} else if ((c->ic_freq >= min) && (c->ic_freq <= max)) {
-+			setflag(c, set);
-+		}
-+	}
-+}
-+
-+static int
-+ieee80211_ioctl_setscanlist(struct net_device *dev,
-+	struct iw_request_info *info,
-+	struct iw_point *data, char *extra)
-+{
-+	struct ieee80211vap *vap = dev->priv;
-+	struct ieee80211com *ic = vap->iv_ic;
-+	char *s, *next;
-+	int val = 1;
-+
-+	if (data->length <= 0)
-+		return -EINVAL;
-+
-+	s = kmalloc(data->length + 1, GFP_KERNEL);
-+	if (!s)
-+		return -ENOMEM;
-+
-+	memset(s, 0, data->length + 1);
-+	if (copy_from_user(s, data->pointer, data->length))
-+		return -EFAULT;
-+
-+	s[data->length - 1] = '\0';		/* ensure null termination */
-+
-+	switch(*s) {
-+		case '-':
-+			val = 1;
-+			break;
-+		case '+':
-+			val = 0;
-+			break;
-+		default:
-+			goto error;
-+	}
-+	s++;
-+	next = s;
-+	do {
-+		next = strchr(s, ',');
-+		if (next) {
-+			*next = 0;
-+			next++;
-+		}
-+		if (!strcmp(s, "ALL")) {
-+			setscanflag(ic, 0, 10000, val);
-+		} else if (!strcmp(s, "REG")) {
-+			setscanflag(ic, -1, -1, val);
-+		} else {
-+			int min, max;
-+			char *n, *end = NULL;
-+
-+			n = strchr(s, '-');
-+			if (n) {
-+				*n = 0;
-+				n++;
-+			}
-+			min = simple_strtoul(s, &end, 10);
-+			if (end && *end)
-+				goto error;
-+			if (n) {
-+				max = simple_strtoul(n, &end, 10);
-+				if (end && *end)
-+					goto error;
-+			} else {
-+				max = min;
-+			}
-+			setscanflag(ic, min, max, val);
-+		}
-+		s = next;
-+	} while (next);
-+	return 0;
-+
-+error:
-+	if (s)
-+		kfree(s);
-+	return -EINVAL;
-+}
-+
- static int
- ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info,
- 	void *w, char *extra)
-@@ -5712,6 +5812,8 @@
- 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
- 	{IEEE80211_PARAM_MINRATE,
- 	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
-+	{ IEEE80211_IOCTL_SETSCANLIST,
-+	 IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
- 	
- #ifdef ATH_REVERSE_ENGINEERING
- 	/*
-@@ -5809,6 +5911,7 @@
- 	set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
- 	set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
- 	set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
-+	set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
- #ifdef ATH_REVERSE_ENGINEERING
- 	set_priv(IEEE80211_IOCTL_READREG, ieee80211_ioctl_readreg),
- 	set_priv(IEEE80211_IOCTL_WRITEREG, ieee80211_ioctl_writereg),
diff --git a/package/madwifi/patches-r3776/316-ani_fix.patch b/package/madwifi/patches-r3776/316-ani_fix.patch
deleted file mode 100644
index ad7deb036..000000000
--- a/package/madwifi/patches-r3776/316-ani_fix.patch
+++ /dev/null
@@ -1,730 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -343,6 +343,8 @@
- 		unsigned int param, unsigned int value);
- 
- static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
-+static int ath_setintmit(struct ath_softc *sc);
-+static u_int32_t ath_calcrxfilter(struct ath_softc *sc);
- 
- #ifdef AR_DEBUG
- static int ath_txq_check(struct ath_softc *sc, struct ath_txq *txq, const char *msg);
-@@ -356,7 +358,6 @@
- static char *ratectl = DEF_RATE_CTL;
- static int rfkill = 0;
- static int hal_tpc = 0;
--static int intmit = 0;
- static int countrycode = CTRY_DEFAULT;
- static int maxvaps = ATH_MAXVAPS_DEFAULT;
- static int outdoor = 0;
-@@ -398,7 +399,6 @@
- #endif
- MODULE_PARM(autocreate, "s");
- MODULE_PARM(ratectl, "s");
--MODULE_PARM(intmit, "i");
- #else
- #include <linux/moduleparam.h>
- module_param(beacon_cal, int, 0600);
-@@ -412,7 +412,6 @@
- #endif
- module_param(autocreate, charp, 0600);
- module_param(ratectl, charp, 0600);
--module_param(intmit, int, 0600);
- #endif
- MODULE_PARM_DESC(countrycode, "Override default country code.  Default is 0.");
- MODULE_PARM_DESC(maxvaps, "Maximum VAPs.  Default is 4.");
-@@ -428,7 +427,6 @@
- 		"'none' to disable");
- MODULE_PARM_DESC(ratectl, "Rate control algorithm [amrr|minstrel|onoe|sample], "
- 		"defaults to '" DEF_RATE_CTL "'");
--MODULE_PARM_DESC(intmit, "Enable interference mitigation by default.  Default is 0.");
- 
- #ifdef AR_DEBUG
- static int	ath_debug = 0;
-@@ -585,23 +583,13 @@
- 	if (ath_hal_hastxpowlimit(ah)) {
- 		ic->ic_caps |= IEEE80211_C_TXPMGT;
- 	}
--	/* Interference mitigation/ambient noise immunity (ANI).
--	 * In modes other than HAL_M_STA, it causes receive sensitivity
--	 * problems for OFDM. */
-+	/* Interference mitigation/ambient noise immunity (ANI). */
- 	sc->sc_hasintmit = ath_hal_hasintmit(ah);
--	sc->sc_useintmit = (intmit && sc->sc_hasintmit);
--	if (!sc->sc_hasintmit && intmit) {
--		WPRINTF(sc, "Interference mitigation was requested, but is not"
--				"supported by the HAL/hardware.\n");
--		intmit = 0; /* Stop use in future ath_attach(). */
--	}
--	else {
--		ath_hal_setintmit(ah, sc->sc_useintmit);
--		DPRINTF(sc, ATH_DEBUG_ANY, "Interference mitigation is "
--			"supported.  Currently %s.\n",
--			(sc->sc_useintmit ? "enabled" : "disabled"));
--	}
- 
-+	/* auto, mode dependent */
-+	sc->sc_useintmit = -1;
-+	sc->sc_noise_immunity = -1;
-+	sc->sc_ofdm_weak_det = -1;
- 	sc->sc_dmasize_stomp = 0;
- 
- 	/*
-@@ -614,15 +602,6 @@
- 	sc->sc_mrretry = ath_hal_setupxtxdesc(ah, NULL, 0,0, 0,0, 0,0);
- 
- 	/*
--	 * Check if the device has hardware counters for PHY
--	 * errors.  If so we need to enable the MIB interrupt
--	 * so we can act on stat triggers.
--	 */
--	sc->sc_needmib = ath_hal_hwphycounters(ah) && 
--		sc->sc_hasintmit && 
--		sc->sc_useintmit;
--
--	/*
- 	 * Get the hardware key cache size.
- 	 */
- 	sc->sc_keymax = ath_hal_keycachesize(ah);
-@@ -1593,37 +1572,6 @@
- 	ath_init(dev);
- }
- 
--/* NB: Int. mit. was not implemented so that it could be enabled/disabled,
-- * and actually in 0.9.30.13 HAL it really can't even be disabled because
-- * it will start adjusting registers even when we turn off the capability
-- * in the HAL.
-- *
-- * NB: This helper function basically clobbers all the related registers
-- * if we have disabled int. mit. cap, allowing us to turn it on and off and
-- * work around the bug preventing it from being disabled. */
--static inline void ath_override_intmit_if_disabled(struct ath_softc *sc) {
--	/* Restore int. mit. registers if they were turned off. */
--	if (sc->sc_hasintmit && !sc->sc_useintmit)
--		ath_hal_restore_default_intmit(sc->sc_ah);
--	/* Sanity check... remove later. */
--	if (!sc->sc_useintmit) {
--		ath_hal_verify_default_intmit(sc->sc_ah);
--		/* If we don't have int. mit. and we don't have DFS on channel,
--		 * it is safe to filter error packets. */
--		if (!ath_radar_is_dfs_required(sc, &sc->sc_curchan)) {
--			ath_hal_setrxfilter(sc->sc_ah,
--				ath_hal_getrxfilter(sc->sc_ah) & 
--				~HAL_RX_FILTER_PHYERR);
--		}
--	}
--	else {
--		/* Make sure that we have errors in RX filter because ANI needs
--		 * them. */
--		ath_hal_setrxfilter(sc->sc_ah, 
--			ath_hal_getrxfilter(sc->sc_ah) | HAL_RX_FILTER_PHYERR);
--	}
--}
--
- static HAL_BOOL ath_hw_reset(struct ath_softc *sc, HAL_OPMODE opmode,
- 		HAL_CHANNEL *channel, HAL_BOOL bChannelChange,
- 		HAL_STATUS *status)
-@@ -1698,11 +1646,7 @@
- 		ath_hal_settpc(sc->sc_ah, hal_tpc);
- 	}
- #endif
--#if 0 /* Setting via HAL does not work, so it is done manually below. */
--	if (sc->sc_hasintmit)
--		ath_hal_setintmit(sc->sc_ah, sc->sc_useintmit);
--#endif
--	ath_override_intmit_if_disabled(sc);
-+	ath_setintmit(sc);
- 	if (sc->sc_dmasize_stomp)
- 		ath_hal_set_dmasize_pcie(sc->sc_ah);
- 	if (sc->sc_softled)
-@@ -2496,7 +2440,6 @@
- 
- 			/* Let the HAL handle the event. */
- 			ath_hal_mibevent(ah, &sc->sc_halstats);
--			ath_override_intmit_if_disabled(sc);
- 		}
- 	}
- 	if (needmark)
-@@ -2564,6 +2507,55 @@
- 	return flags;
- }
- 
-+static int ath_setintmit(struct ath_softc *sc)
-+{
-+	struct ath_hal *ah = sc->sc_ah;
-+	int ret;
-+	int val;
-+
-+	if (!sc->sc_hasintmit)
-+		return 0;
-+
-+	switch(sc->sc_useintmit) {
-+		case 0: /* disabled */
-+		case 1: /* enabled */
-+			val = sc->sc_useintmit;
-+			break;
-+		default:
-+			if (sc->sc_opmode != IEEE80211_M_MONITOR)
-+				val = 1;
-+			else
-+				val = 0;
-+			break;
-+	}
-+	ret = ath_hal_setintmit(ah, val);
-+	if (val)
-+		goto done;
-+
-+	/* manual settings */
-+	if ((sc->sc_noise_immunity >= 0) && (sc->sc_noise_immunity <= 5))
-+		ath_hal_setcapability(ah, HAL_CAP_INTMIT, 2, sc->sc_noise_immunity, NULL);
-+	if ((sc->sc_ofdm_weak_det == 0) || (sc->sc_ofdm_weak_det == 1))
-+		ath_hal_setcapability(ah, HAL_CAP_INTMIT, 3, sc->sc_ofdm_weak_det, NULL);
-+
-+done:
-+	if (!sc->sc_imask)
-+		goto out;
-+
-+	/* MIB interrupt handling */
-+	sc->sc_needmib = ath_hal_hwphycounters(ah) &&
-+		sc->sc_useintmit;
-+	if (sc->sc_needmib)
-+		sc->sc_imask |= HAL_INT_MIB;
-+	else
-+		sc->sc_imask &= ~HAL_INT_MIB;
-+	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
-+	ath_calcrxfilter(sc);
-+
-+out:
-+	return ret;
-+}
-+
- /*
-  * Context: process context
-  */
-@@ -4249,8 +4241,7 @@
- 	u_int32_t rfilt;
- 
- 	/* Preserve the current Phy. radar and err. filters. */
--	rfilt = (ath_hal_getrxfilter(ah) &
--			(HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)) |
-+	rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYRADAR) |
- 		 HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST |
- 		 HAL_RX_FILTER_MCAST;
- 	if (ic->ic_opmode != IEEE80211_M_STA)
-@@ -4266,6 +4257,8 @@
- 	if (sc->sc_nmonvaps > 0)
- 		rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
- 			  HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM);
-+	if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL))
-+		rfilt |= HAL_RX_FILTER_PHYERR;
- 	if (sc->sc_curchan.privFlags & CHANNEL_DFS)
- 		rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
- 	return rfilt;
-@@ -6810,8 +6803,7 @@
- 	dev->quota -= bf_processed;
- #endif
- 
--	if (sc->sc_useintmit) 
--		ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
-+	ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
- 	if (!bf_processed)
- 		DPRINTF(sc, ATH_DEBUG_RX_PROC,
- 			"Warning: %s got scheduled when no receive "
-@@ -8727,7 +8719,6 @@
- 	ath_hal_rxena(ah);		/* enable recv descriptors */
- 	ath_mode_init(dev);		/* set filters, etc. */
- 	ath_hal_startpcurecv(ah);	/* re-enable PCU/DMA engine */
--	ath_override_intmit_if_disabled(sc);
- 	return 0;
- }
- 
-@@ -10633,8 +10624,10 @@
- 	ATH_RP_IGNORED 		= 24,
- 	ATH_RADAR_IGNORED       = 25,
- 	ATH_MAXVAPS  		= 26,
--        ATH_INTMIT 		= 27,
--	ATH_DISTANCE		= 28,
-+	ATH_DISTANCE		= 27,
-+	ATH_INTMIT			= 28,
-+	ATH_NOISE_IMMUNITY	= 29,
-+	ATH_OFDM_WEAK_DET	= 30
- };
- 
- static inline int 
-@@ -10696,6 +10689,48 @@
- }
- 
- static int
-+ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val)
-+{
-+	int ret;
-+
-+	switch(ctl) {
-+	case ATH_INTMIT:
-+		sc->sc_intmit = val;
-+		break;
-+	case ATH_NOISE_IMMUNITY:
-+		sc->sc_noise_immunity = val;
-+		break;
-+	case ATH_OFDM_WEAK_DET:
-+		sc->sc_ofdm_weak_det = val;
-+		break;
-+	default:
-+		return -EINVAL;
-+	}
-+	ret = ath_setintmit(sc);
-+	return ret;
-+}
-+
-+static int
-+ath_sysctl_get_intmit(struct ath_softc *sc, long ctl, u_int *val)
-+{
-+	struct ath_hal *ah = sc->sc_ah;
-+
-+	switch(ctl) {
-+	case ATH_INTMIT:
-+		*val = (ath_hal_getcapability(ah, HAL_CAP_INTMIT, 1, NULL) == HAL_OK);
-+		break;
-+	case ATH_NOISE_IMMUNITY:
-+		return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 2, val);
-+	case ATH_OFDM_WEAK_DET:
-+		return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 3, val);
-+	default:
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
-+
-+
-+static int
- ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
- {
- 	struct ath_softc *sc = ctl->extra1;
-@@ -10934,30 +10969,13 @@
- 				sc->sc_radar_ignored = val;
- 				break;
- 			case ATH_INTMIT:
--				if (!sc->sc_hasintmit) {
-+			case ATH_NOISE_IMMUNITY:
-+			case ATH_OFDM_WEAK_DET:
-+				if (!sc->sc_hasintmit)
- 					ret = -EOPNOTSUPP;
--					break;
--				}
--				if (sc->sc_useintmit == val)
--					break;
--				sc->sc_useintmit = val; 
--				sc->sc_needmib = ath_hal_hwphycounters(ah) && 
--					sc->sc_useintmit;
--				/* Update the HAL and MIB interrupt mask bits */
--				ath_hal_setintmit(ah, !!val); 
--				sc->sc_imask = (sc->sc_imask & ~HAL_INT_MIB) | 
--					(sc->sc_needmib ? HAL_INT_MIB : 0);
--				ath_hal_intrset(sc->sc_ah, sc->sc_imask);
--				/* Only do a reset if device is valid and UP 
--				 * and we just made a change to the settings. */
--				if (sc->sc_dev && !sc->sc_invalid &&
--				    (sc->sc_dev->flags & IFF_RUNNING))
--					ath_reset(sc->sc_dev); 
--				/* NB: Run this step to cleanup if HAL doesn't 
--				 * obey capability flags and hangs onto ANI
--				 * settings. */
--				ath_override_intmit_if_disabled(sc);
--                                break; 
-+				else
-+					ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
-+				break;
- 			default:
- 				ret = -EINVAL;
- 				break;
-@@ -11029,9 +11047,14 @@
- 		case ATH_RADAR_IGNORED:
- 			val = sc->sc_radar_ignored;
- 			break;
--                case ATH_INTMIT: 
--			val = sc->sc_useintmit; 
--			break; 
-+		case ATH_INTMIT:
-+		case ATH_NOISE_IMMUNITY:
-+		case ATH_OFDM_WEAK_DET:
-+			if (!sc->sc_hasintmit)
-+				ret = -EOPNOTSUPP;
-+			else
-+				ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
-+			break;
- 		default:
- 			ret = -EINVAL;
- 			break;
-@@ -11413,6 +11436,24 @@
- 	  .maxlen	= sizeof(ath_xchanmode),
- 	  .proc_handler	= proc_dointvec
- 	},
-+	{ .ctl_name	= CTL_AUTO,
-+	  .procname     = "intmit",
-+	  .mode         = 0644,
-+	  .proc_handler = ath_sysctl_halparam,
-+	  .extra2	= (void *)ATH_INTMIT,
-+	},
-+	{ .ctl_name	= CTL_AUTO,
-+	  .procname     = "noise_immunity",
-+	  .mode         = 0644,
-+	  .proc_handler = ath_sysctl_halparam,
-+	  .extra2	= (void *)ATH_NOISE_IMMUNITY,
-+	},
-+	{ .ctl_name	= CTL_AUTO,
-+	  .procname     = "ofdm_weak_det",
-+	  .mode         = 0644,
-+	  .proc_handler = ath_sysctl_halparam,
-+	  .extra2	= (void *)ATH_OFDM_WEAK_DET,
-+	},
- 	{ 0 }
- };
- static ctl_table ath_ath_table[] = {
---- a/ath/if_athvar.h
-+++ b/ath/if_athvar.h
-@@ -712,6 +712,10 @@
- 	unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */
- 	unsigned int sc_txcont_rate;  /* Continuous transmit rate in Mbps */
- 
-+	int8_t sc_intmit; /* Interference mitigation enabled, -1 = auto, based on mode, 0/1 = off/on */
-+	int8_t sc_noise_immunity; /* Noise immunity level, 0-4, -1 == auto) */
-+	int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */
-+
- 	/* rate tables */
- 	const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
- 	const HAL_RATE_TABLE *sc_currates;	/* current rate table */
---- a/ath/if_ath_hal_extensions.h
-+++ b/ath/if_ath_hal_extensions.h
-@@ -237,296 +237,18 @@
- 	AR5K_DMASIZE_512B
- };
- 
--
--int ath_set_ack_bitrate(struct ath_softc *sc, int);
--int ar_device(int devid);
--const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
--
--static inline unsigned long field_width(unsigned long mask, unsigned long shift)
--{
--	unsigned long r = 0;
--	unsigned long x = mask >> shift;
--	if ( 0 == mask )  return  0;
--#if  BITS_PER_LONG >= 64
--	if ( x & (~0UL<<32) )  { x >>= 32;  r += 32; }
--#endif
--	if ( x & 0xffff0000 )  { x >>= 16;  r += 16; }
--	if ( x & 0x0000ff00 )  { x >>=  8;  r +=  8; }
--	if ( x & 0x000000f0 )  { x >>=  4;  r +=  4; }
--	if ( x & 0x0000000c )  { x >>=  2;  r +=  2; }
--	if ( x & 0x00000002 )  {            r +=  1; }
--	return r+1;
--}
--
--static inline u_int32_t get_field(struct ath_hal *ah, u_int32_t reg, u_int32_t mask, u_int32_t shift, int is_signed) {
--	unsigned long x = ((OS_REG_READ(ah, reg) & mask) >> shift);
--	if (is_signed) {
--		unsigned long c =(-1) << (field_width(mask, shift)-1);
--		return (x + c) ^ c;
--	}
--	return x;
--}
--
- static inline void set_field(struct ath_hal *ah, u_int32_t reg, u_int32_t mask, u_int32_t shift, u_int32_t value) {
- 	OS_REG_WRITE(ah, reg, 
- 			  (OS_REG_READ(ah, reg) & ~mask) | 
- 			  ((value << shift) & mask));
- }
- 
--static inline u_int32_t field_eq(struct ath_hal *ah, u_int32_t reg, 
--				 u_int32_t mask, u_int32_t shift, 
--				 u_int32_t value, int is_signed) {
--	return  (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)) == 
--		(value & (mask >> shift));
--}
--
--static inline void override_warning(struct ath_hal *ah, const char *name,
--				    u_int32_t reg, u_int32_t mask,
--				    u_int32_t shift, u_int32_t expected, int is_signed) {
--
--	if (!field_eq(ah, reg, mask, shift, expected, is_signed)) 
--		printk("%s: Correcting 0x%04x[%s] from 0x%x (%d) to 0x%x (%d).\n", 
--		       SC_DEV_NAME(ah->ah_sc),
--		       reg,
--		       name, 
--		       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)),
--		       get_field(ah, reg, mask, shift, is_signed), 
--		       (expected & (mask >> shift)), /* not sign extended */
--		       expected);
--#if 0 /* NB: For checking to see if HAL is fixed or not */
--	else {
--			printk("%s: Keeping 0x%04x[%s] - 0x%x (%d).\n",
--			       SC_DEV_NAME(ah->ah_sc),
--			       reg,
--			       name, 
--			       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)),
--			       get_field(ah, reg, mask, shift, is_signed));
--	}
--#endif
--}
--
--static inline void verification_warning(struct ath_hal *ah, const char *name,
--    u_int32_t reg, u_int32_t mask, 
--    u_int32_t shift, u_int32_t expected, int is_signed) {
--
--	int ret = field_eq(ah, reg, mask, shift, expected, is_signed);
--	if (!ret) {
--		printk("%s: %s verification of %s default value "
--		       "[found=0x%x (%d) expected=0x%x (%d)].\n", 
--		       SC_DEV_NAME(ah->ah_sc),
--		       (ret ? "PASSED" : "FAILED"),
--			name, 
--		       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)), 
--		       get_field(ah, reg, mask, shift, is_signed), 
--		       (expected & (mask >> shift)), /* not sign extended */
--		       expected);
--		ath_hal_print_decoded_register(ah, NULL, reg, 
--					       OS_REG_READ(ah, reg), OS_REG_READ(ah, reg), 0);
--	}
--}
--
--#define GET_FIELD(ah, __reg, __mask, __signed) \
--	get_field(ah, __reg, __mask, __mask ## _S, __signed)
- #define SET_FIELD(ah, __reg, __mask, __value) \
- 	set_field(ah, __reg, __mask, __mask ## _S, __value);
--#define FIELD_EQ(ah, __reg, __mask, __value, __signed) \
--	field_eq(ah, __reg, __mask, __mask ## _S, __value, __signed)
--
--#if 0 /* NB: These are working at this point, and HAL tweaks them a lot */
--#define OVERRIDE_WARNING(ah, __reg, __mask, __expected, __signed) \
--	override_warning(ah, #__mask, __reg, __mask, __mask ## _S, __expected, __signed)
--#else
--#define OVERRIDE_WARNING(ah, __reg, __mask, __expected, __signed) 
--#endif
--	
--#define VERIFICATION_WARNING(ah, __reg, __mask, __signed) \
--	verification_warning(ah, #__mask, __reg, __mask, __mask ## _S, DEFAULT_ ## __mask, __signed)
--#define VERIFICATION_WARNING_SW(ah, __reg, __mask, __signed) \
--	verification_warning(ah, #__mask, __reg, __mask, __mask ## _S, DEFAULT_ENABLE_ ## __reg ? __mask ## _ON : __mask ## _OFF, __signed)
--
--static inline void ath_hal_set_noise_immunity(struct ath_hal *ah,
--					      int agc_desired_size, 
--					      int agc_coarse_hi,
--					      int agc_coarse_lo, 
--					      int sig_firpwr) 
--{
--	ATH_HAL_LOCK_IRQ(ah->ah_sc);
--	ath_hal_set_function(__func__);
--	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
--
--#if 0 /* NB: These are working at this point, and HAL tweaks them a lot */
--	OVERRIDE_WARNING(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, agc_desired_size, 1);
--	OVERRIDE_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, agc_coarse_lo, 1);
--	OVERRIDE_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, agc_coarse_hi, 1);
--	OVERRIDE_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, sig_firpwr, 1);
--#endif
--
--	SET_FIELD(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, agc_desired_size);
--	SET_FIELD(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, agc_coarse_lo);
--	SET_FIELD(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, agc_coarse_hi);
--	SET_FIELD(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, sig_firpwr);
--
--	ath_hal_set_function(NULL);
--	ath_hal_set_device(NULL);
--	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
--}
--
--static inline void ath_hal_set_ofdm_weak_det(struct ath_hal *ah, 
--	int low_m1, int low_m2, int low_m2_count, int low_self_corr,
--	int high_m1, int high_m2, int high_m2_count)
--{
--	ATH_HAL_LOCK_IRQ(ah->ah_sc);
--	ath_hal_set_function(__func__);
--	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
--
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, low_m1, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, low_m2, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, low_m2_count, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, low_self_corr, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, high_m1, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, high_m2, 0);
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, high_m2_count, 0);
--
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, low_m1);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, low_m2);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, low_m2_count);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, low_self_corr);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, high_m1);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, high_m2);
--	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, high_m2_count);
--
--	ath_hal_set_function(NULL);
--	ath_hal_set_device(NULL);
--	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
--}
--
--static inline void ath_hal_set_cck_weak_det(struct ath_hal *ah, int thresh)
--{
--	ATH_HAL_LOCK_IRQ(ah->ah_sc);
--	ath_hal_set_function(__func__);
--	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
--
--	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, thresh, 0);
--
--	SET_FIELD(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, thresh);
--
--	ath_hal_set_function(NULL);
--	ath_hal_set_device(NULL);
--	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
--}
--
--static inline void ath_hal_set_sig_firstep(struct ath_hal *ah, int firstep)
--{
--	ATH_HAL_LOCK_IRQ(ah->ah_sc);
--	ath_hal_set_function(__func__);
--	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
- 
--	OVERRIDE_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, firstep, 0);
--
--	SET_FIELD(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, firstep);
--
--	ath_hal_set_function(NULL);
--	ath_hal_set_device(NULL);
--	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
--}
--
--static inline void ath_hal_set_spur_immunity(struct ath_hal *ah, int thresh)
--{
--	ATH_HAL_LOCK_IRQ(ah->ah_sc);
--	ath_hal_set_function(__func__);
--	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
--
--	OVERRIDE_WARNING(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, thresh, 0);
--
--	SET_FIELD(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, thresh);
--
--	ath_hal_set_function(NULL);
--	ath_hal_set_device(NULL);
--	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
--}
--
--static inline void ath_hal_restore_default_noise_immunity(struct ath_hal *ah) {
--
--	ath_hal_set_noise_immunity(ah, 
--		DEFAULT_AR5K_PHY_AGCSIZE_DESIRED, 
--		DEFAULT_AR5K_PHY_AGCCOARSE_HI,
--		DEFAULT_AR5K_PHY_AGCCOARSE_LO,
--		DEFAULT_AR5K_PHY_SIG_FIRPWR);
--}
--
--static inline void ath_hal_enable_ofdm_weak_det(struct ath_hal *ah, int enable) {
--	if (enable)
--		ath_hal_set_ofdm_weak_det(ah, 
--			AR5K_PHY_WEAK_OFDM_LOW_M1_ON,
--			AR5K_PHY_WEAK_OFDM_LOW_M2_ON,
--			AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT_ON,
--		        AR5K_PHY_WEAK_OFDM_LOW_SELFCOR_ON,
--			AR5K_PHY_WEAK_OFDM_HIGH_M1_ON,
--			AR5K_PHY_WEAK_OFDM_HIGH_M2_ON,
--			AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT_ON);
--	else
--		ath_hal_set_ofdm_weak_det(ah, 
--			AR5K_PHY_WEAK_OFDM_LOW_M1_OFF,
--			AR5K_PHY_WEAK_OFDM_LOW_M2_OFF,
--			AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT_OFF,
--			AR5K_PHY_WEAK_OFDM_LOW_SELFCOR_OFF,
--			AR5K_PHY_WEAK_OFDM_HIGH_M1_OFF,
--			AR5K_PHY_WEAK_OFDM_HIGH_M2_OFF,
--			AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT_OFF);
--}
--
--static inline void ath_hal_enable_cck_weak_det(struct ath_hal *ah, int enable) {
--	ath_hal_set_cck_weak_det(ah, enable 
--				 ? AR5K_PHY_WEAK_CCK_THRESH_ON 
--				 : AR5K_PHY_WEAK_CCK_THRESH_OFF);
--}
--
--static inline void ath_hal_restore_default_ofdm_weak_det(struct ath_hal *ah) {
--	ath_hal_enable_ofdm_weak_det(ah, DEFAULT_ENABLE_AR5K_PHY_WEAK_OFDM);
--}
--
--static inline void ath_hal_restore_default_cck_weak_det(struct ath_hal *ah) {
--	ath_hal_enable_cck_weak_det(ah, DEFAULT_ENABLE_AR5K_PHY_WEAK_CCK);
--}
--
--static inline void ath_hal_restore_default_sig_firstep(struct ath_hal *ah) {
--
--	ath_hal_set_sig_firstep(ah, 
--		DEFAULT_AR5K_PHY_SIG_FIRSTEP);
--}
--
--static inline void ath_hal_restore_default_spur_immunity(struct ath_hal *ah) {
--
--	ath_hal_set_spur_immunity(ah, 
--		DEFAULT_AR5K_PHY_SPUR_THRESH);
--}
--
--static inline void ath_hal_restore_default_intmit(struct ath_hal *ah) {
--	ath_hal_restore_default_noise_immunity(ah);
--	ath_hal_restore_default_ofdm_weak_det(ah);
--	ath_hal_restore_default_cck_weak_det(ah);
--	ath_hal_restore_default_sig_firstep(ah);
--	ath_hal_restore_default_spur_immunity(ah);
--
--}
--
--static inline void ath_hal_verify_default_intmit(struct ath_hal *ah) {
--	/* Just a list of all the fields above, for sanity checks... */
--	VERIFICATION_WARNING(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, 1);
--	VERIFICATION_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, 1);
--	VERIFICATION_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, 1);
--	VERIFICATION_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, 1);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, 0);
--	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, 0);
--	VERIFICATION_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, 0);
--	VERIFICATION_WARNING(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, 0);
--}
-+int ath_set_ack_bitrate(struct ath_softc *sc, int);
-+int ar_device(int devid);
-+const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
- 
- static inline void ath_hal_set_dmasize_pcie(struct ath_hal *ah) {
- 	SET_FIELD(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
---- a/ath/if_ath_hal.h
-+++ b/ath/if_ath_hal.h
-@@ -79,7 +79,7 @@
- 	ath_hal_set_function(__func__);
- 	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
- 	ret =
--	    ah->ah_getDiagState(ah, request, args, argsize, *result,
-+	    ah->ah_getDiagState(ah, request, args, argsize, result,
- 				resultsize);
- 	ath_hal_set_function(NULL);
- 	ath_hal_set_device(NULL);
---- a/scripts/if_ath_hal_generator.pl
-+++ b/scripts/if_ath_hal_generator.pl
-@@ -145,7 +145,9 @@
-     "ah_waitForBeaconDone"        => "ath_hal_waitforbeacon",
-     "ah_writeAssocid"             => "ath_hal_setassocid",
-     "ah_clrMulticastFilterIndex"  => "ath_hal_clearmcastfilter",
--    "ah_detectCardPresent"        => "ath_hal_detectcardpresent"
-+    "ah_detectCardPresent"        => "ath_hal_detectcardpresent",
-+    "ah_setSifsTime"              => "ath_hal_setsifstime",
-+    "ah_getSifsTime"              => "ath_hal_getsifstime"
- );
- 
- #
-@@ -254,7 +256,7 @@
- 
-     foreach (@parameters) {
-         s/ \*/\* /;
--        /^((?:(?:const|struct|\*)\s*)*)([^\s]+\*?)\s*([^\s]*)\s*/;
-+        /^((?:(?:const|struct|\*)\s*)*)([^\s]+\**)\s*([^\s]*)\s*/;
-         my $type = "$1$2";
-         my $name = "$3";
-         if ( 0 == length($name) ) {
diff --git a/package/madwifi/patches-r3776/317-devid.patch b/package/madwifi/patches-r3776/317-devid.patch
deleted file mode 100644
index 281e348f8..000000000
--- a/package/madwifi/patches-r3776/317-devid.patch
+++ /dev/null
@@ -1,17 +0,0 @@
---- a/ath/if_ath_pci.c
-+++ b/ath/if_ath_pci.c
-@@ -114,11 +114,13 @@
- 	{ 0x168c, 0x0023, PCI_ANY_ID, PCI_ANY_ID },
- 	{ 0x168c, 0x0024, PCI_ANY_ID, PCI_ANY_ID },
- 	{ 0x168c, 0x9013, PCI_ANY_ID, PCI_ANY_ID }, /* sonicwall */
-+	{ 0x168c, 0xff1a, PCI_ANY_ID, PCI_ANY_ID },
- 	{ 0 }
- };
- 
- static u16 ath_devidmap[][2] = {
--	{ 0x9013, 0x0013 }
-+	{ 0x9013, 0x0013 },
-+	{ 0xff1a, 0x001a }
- };
- 
- static int
diff --git a/package/madwifi/patches-r3776/318-ifxmips_eeprom.patch b/package/madwifi/patches-r3776/318-ifxmips_eeprom.patch
deleted file mode 100644
index 412ceadeb..000000000
--- a/package/madwifi/patches-r3776/318-ifxmips_eeprom.patch
+++ /dev/null
@@ -1,85 +0,0 @@
---- a/ath_hal/ah_os.c
-+++ b/ath_hal/ah_os.c
-@@ -917,9 +917,56 @@
-  * NB: see the comments in ah_osdep.h about byte-swapping register
-  *     reads and writes to understand what's going on below.
-  */
-+
-+#ifdef CONFIG_IFXMIPS
-+extern int ifxmips_has_brn_block(void);
-+static int ifxmips_emulate = 0;
-+#define EEPROM_EMULATION 1
-+#endif
-+
-+#ifdef EEPROM_EMULATION
-+static int ath_hal_eeprom(struct ath_hal *ah, unsigned long addr, int val, int write)
-+{
-+	static int addrsel = 0;
-+	static int rc = 0;
-+
-+	if (write) {
-+		if(addr == 0x6000) {
-+			addrsel = val * 2;
-+			rc = 0;
-+		}
-+	} else {
-+		switch(addr)
-+		{
-+		case 0x600c:
-+			if(rc++ < 2)
-+				val = 0x00000000;
-+			else
-+				val = 0x00000002;
-+			break;
-+		case 0x6004:
-+			val = cpu_to_le16(__raw_readw((u16 *) KSEG1ADDR(0xb07f0400 + addrsel)));
-+			/* this forces the regdomain to 0x00 (worldwide), as the original setting
-+			 * causes issues with the HAL */
-+			if (addrsel == 0x17e)
-+				val = 0;
-+			break;
-+		}
-+	}
-+	return val;
-+}
-+#endif
-+
- void __ahdecl
- ath_hal_reg_write(struct ath_hal *ah, u_int address, u_int32_t value)
- {
-+#ifdef EEPROM_EMULATION
-+	if((address >= 0x6000) && (address <= 0x6010) && ifxmips_emulate) {
-+		ath_hal_eeprom(ah, address, value, 1);
-+		return;
-+	}
-+#endif
-+
- 	_trace_regop(ah, REGOP_WRITE, address, value);
- 	_OS_REG_WRITE(ah, address, value);
- }
-@@ -929,7 +976,14 @@
- u_int32_t __ahdecl
- ath_hal_reg_read(struct ath_hal *ah, u_int address)
- {
-- 	u_int32_t val = _OS_REG_READ(ah, address);
-+	u_int32_t val;
-+
-+#ifdef EEPROM_EMULATION
-+	if((address >= 0x6000) && (address <= 0x6010) && ifxmips_emulate)
-+		val = ath_hal_eeprom(ah, address, 0, 0);
-+	else
-+#endif
-+		val = _OS_REG_READ(ah, address);
- 	_trace_regop(ah, REGOP_READ, address, val);
- 	return val;
- }
-@@ -1123,6 +1177,9 @@
- #ifdef MMIOTRACE
- 	kmmio_logmsg = _kmmio_logmsg;
- #endif
-+#ifdef CONFIG_IFXMIPS
-+	ifxmips_emulate = ifxmips_has_brn_block();
-+#endif
- 
- 	sep = "";
- 	for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
diff --git a/package/madwifi/patches-r3776/319-eap_auth_disassoc.patch b/package/madwifi/patches-r3776/319-eap_auth_disassoc.patch
deleted file mode 100644
index a1d9b0ba4..000000000
--- a/package/madwifi/patches-r3776/319-eap_auth_disassoc.patch
+++ /dev/null
@@ -1,81 +0,0 @@
-This patch causes STA mode interfaces to disassociate if transmission of assoc/auth
-critical packets failed.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -8273,6 +8273,18 @@
- #endif
- 				if (ts->ts_status & HAL_TXERR_XRETRY) {
- 					sc->sc_stats.ast_tx_xretries++;
-+					if (SKB_CB(bf->bf_skb)->auth_pkt && (ni->ni_vap->iv_opmode == IEEE80211_M_STA)) {
-+						struct ieee80211com *ic = &sc->sc_ic;
-+
-+						/* if roaming is enabled, try reassociating, otherwise
-+						 * disassociate and go back to the scan state */
-+						IEEE80211_VAPS_LOCK_BH(ic);
-+						if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
-+							ni->ni_vap->iv_newstate(ni->ni_vap, IEEE80211_S_ASSOC, 1);
-+						else
-+							ni->ni_vap->iv_newstate(ni->ni_vap, IEEE80211_S_SCAN, 0);
-+						IEEE80211_VAPS_UNLOCK_BH(ic);
-+					}
- 					if (ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) {
- 						ni->ni_stats.ns_tx_eosplost++;
- 						DPRINTF(sc, ATH_DEBUG_UAPSD,
---- a/net80211/ieee80211_linux.c
-+++ b/net80211/ieee80211_linux.c
-@@ -158,6 +158,7 @@
- 
- 		SKB_NI(skb) = NULL;
- 		SKB_CB(skb)->flags = 0;
-+		SKB_CB(skb)->auth_pkt = 0;
- 
- 		skb_reserve(skb, sizeof(struct ieee80211_frame));
- 		*frm = skb_put(skb, pktlen);
---- a/net80211/ieee80211_linux.h
-+++ b/net80211/ieee80211_linux.h
-@@ -411,6 +411,7 @@
- #define M_SKB_TRACKED	0x20
- 	void		(*next_destructor)(struct sk_buff *skb);
- #endif
-+	u_int8_t auth_pkt;
- };
- 
- struct __assert {
---- a/net80211/ieee80211_output.c
-+++ b/net80211/ieee80211_output.c
-@@ -773,6 +773,8 @@
- 	else
- 		hdrsize = sizeof(struct ieee80211_frame);
- 
-+	SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
-+
- 	switch (vap->iv_opmode) {
- 	case IEEE80211_M_IBSS:
- 	case IEEE80211_M_AHDEMO:
-@@ -1617,6 +1619,7 @@
- 	ie->param_len = frm - &ie->param_oui[0];
- 	return frm;
- }
-+
- #endif
- /*
-  * Send a probe request frame with the specified ssid
-@@ -1881,6 +1884,7 @@
- 				sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0));
- 		if (skb == NULL)
- 			senderr(ENOMEM, is_tx_nobuf);
-+		SKB_CB(skb)->auth_pkt = 1;
- 
- 		((__le16 *)frm)[0] =
- 			(is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
-@@ -1955,6 +1959,7 @@
- 			vap->app_ie[IEEE80211_APPIE_FRAME_ASSOC_REQ].length);
- 		if (skb == NULL)
- 			senderr(ENOMEM, is_tx_nobuf);
-+		SKB_CB(skb)->auth_pkt = 1;
- 
- 		capinfo = 0;
- 		if (vap->iv_opmode == IEEE80211_M_IBSS)
diff --git a/package/madwifi/patches-r3776/320-hidden_ssid.patch b/package/madwifi/patches-r3776/320-hidden_ssid.patch
deleted file mode 100644
index 92d0480d2..000000000
--- a/package/madwifi/patches-r3776/320-hidden_ssid.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-This patch fixes the detection of hidden SSIDs as transmitted
-by some cisco systems.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_scan_sta.c
-+++ b/net80211/ieee80211_scan_sta.c
-@@ -209,6 +209,19 @@
- 		ieee80211_saveie(iep, ie);
- }
- 
-+
-+static inline int is_empty_ssid(u_int8_t *ssid)
-+{
-+	if (!ssid)
-+		return 1;
-+	if (ssid[1] == 0)
-+		return 1;
-+	if ((ssid[1] == 1) && (ssid[2] == 0))
-+		return 1;
-+	return 0;
-+}
-+
-+
- /*
-  * Process a beacon or probe response frame; create an
-  * entry in the scan cache or update any previous entry.
-@@ -252,8 +265,8 @@
- 	ise = &se->base;
- 
- 	/* XXX ap beaconing multiple ssid w/ same bssid */
--	if (sp->ssid[1] != 0 &&
--	    (ISPROBE(subtype) || ise->se_ssid[1] == 0))
-+	if (!is_empty_ssid(sp->ssid) &&
-+	    (ISPROBE(subtype) || is_empty_ssid(ise->se_ssid)))
- 		memcpy(ise->se_ssid, sp->ssid, 2 + sp->ssid[1]);
- 
- 	memcpy(ise->se_rates, sp->rates, 
diff --git a/package/madwifi/patches-r3776/321-bgscan_rssi_thresh.patch b/package/madwifi/patches-r3776/321-bgscan_rssi_thresh.patch
deleted file mode 100644
index 7020305ea..000000000
--- a/package/madwifi/patches-r3776/321-bgscan_rssi_thresh.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-Add an optional background scanning threshold triggered by low rssi
-(useful for passing updated scan results to the supplicant ahead of
-time, before losing connectivity entirely)
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -655,6 +655,7 @@
- 	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
- 	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
- 	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
-+	IEEE80211_PARAM_BGSCAN_THRESH		= 87,	/* bg scan rssi threshold */
- };
- 
- #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -92,6 +92,8 @@
- #define	IEEE80211_BGSCAN_IDLE_MIN	100	/* min idle time (ms) */
- #define	IEEE80211_BGSCAN_IDLE_DEFAULT	250	/* default idle time (ms) */
- 
-+#define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */
-+
- #define IEEE80211_COVERAGE_CLASS_MAX	31	/* max coverage class */
- #define IEEE80211_REGCLASSIDS_MAX	10	/* max regclass id list */
- 
-@@ -229,6 +231,9 @@
- 	u_int8_t iv_nickname[IEEE80211_NWID_LEN];
- 	u_int iv_bgscanidle;				/* bg scan idle threshold */
- 	u_int iv_bgscanintvl;				/* bg scan min interval */
-+	u_int iv_bgscanthr;					/* bg scan rssi threshold */
-+	u_int iv_bgscantrintvl;				/* bg scan trigger interval */
-+	unsigned long iv_bgscanthr_next;		/* last trigger for bgscan */
- 	u_int iv_scanvalid;				/* scan cache valid threshold */
- 	struct ieee80211_roam iv_roam;			/* sta-mode roaming state */
- 
-@@ -612,6 +617,7 @@
- #define IEEE80211_FEXT_SWBMISS		0x00000400	/* CONF: use software beacon timer */
- #define IEEE80211_FEXT_DROPUNENC_EAPOL	0x00000800	/* CONF: drop unencrypted eapol frames */
- #define IEEE80211_FEXT_APPIE_UPDATE	0x00001000	/* STATE: beacon APP IE updated */
-+#define IEEE80211_FEXT_BGSCAN_THR	0x00002000	/* bgscan due to low rssi */
- 
- #define IEEE80211_COM_UAPSD_ENABLE(_ic)		((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD)
- #define IEEE80211_COM_UAPSD_DISABLE(_ic)	((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD)
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -2778,6 +2778,9 @@
- 		else
- 			retv = EINVAL;
- 		break;
-+	case IEEE80211_PARAM_BGSCAN_THRESH:
-+		vap->iv_bgscanthr = value;
-+		break;
- 	case IEEE80211_PARAM_MCAST_RATE:
- 		/* units are in KILObits per second */
- 		if (value >= 256 && value <= 54000)
-@@ -3181,6 +3184,9 @@
- 	case IEEE80211_PARAM_BGSCAN_INTERVAL:
- 		param[0] = vap->iv_bgscanintvl / HZ;	/* seconds */
- 		break;
-+	case IEEE80211_PARAM_BGSCAN_THRESH:
-+		param[0] = vap->iv_bgscanthr;	/* rssi */
-+		break;
- 	case IEEE80211_PARAM_MCAST_RATE:
- 		param[0] = vap->iv_mcast_rate;	/* seconds */
- 		break;
-@@ -5704,6 +5710,10 @@
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanintvl" },
- 	{ IEEE80211_PARAM_BGSCAN_INTERVAL,
- 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanintvl" },
-+	{ IEEE80211_PARAM_BGSCAN_THRESH,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanthr" },
-+	{ IEEE80211_PARAM_BGSCAN_THRESH,
-+	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanthr" },
- 	{ IEEE80211_PARAM_MCAST_RATE,
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcast_rate" },
- 	{ IEEE80211_PARAM_MCAST_RATE,
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -2984,8 +2984,10 @@
- {
- 	struct ieee80211com *ic = vap->iv_ic;
- 
-+	vap->iv_bgscantrintvl = (vap->iv_bgscantrintvl + 1) % 4;
- 	return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
--		time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle));
-+		(((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && !vap->iv_bgscantrintvl) ||
-+			time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)));
- }
- 
- static __inline int
-@@ -3229,6 +3231,23 @@
- 			/* record tsf of last beacon */
- 			memcpy(ni->ni_tstamp.data, scan.tstamp,
- 				sizeof(ni->ni_tstamp));
-+
-+			/* When rssi is low, start doing bgscans more frequently to allow
-+			 * the supplicant to make a better switching decision */
-+			if ((rssi < vap->iv_bgscanthr) &&
-+					(!vap->iv_bgscanthr_next ||
-+						!time_before(jiffies, vap->iv_bgscanthr_next)) &&
-+					!(ic->ic_flags & IEEE80211_F_SCAN)) {
-+				int ret;
-+
-+				ic->ic_lastdata = 0;
-+				ic->ic_lastscan = 0;
-+				ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN_THR;
-+				ret = ieee80211_bg_scan(vap);
-+				if (ret)
-+					vap->iv_bgscanthr_next = jiffies + msecs_to_jiffies(IEEE80211_BGSCAN_TRIGGER_INTVL * 1000);
-+			}
-+
- 			if (ni->ni_intval != scan.bintval) {
- 				IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
- 						"beacon interval divergence: "
---- a/net80211/ieee80211_scan.c
-+++ b/net80211/ieee80211_scan.c
-@@ -793,7 +793,7 @@
- 				ieee80211_sta_pwrsave(vap, 0);
- 				if (ss->ss_next >= ss->ss_last) {
- 					ieee80211_notify_scan_done(vap);
--					ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
-+					ic->ic_flags_ext &= ~(IEEE80211_FEXT_BGSCAN|IEEE80211_FEXT_BGSCAN_THR);
- 				}
- 			}
- 			SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
diff --git a/package/madwifi/patches-r3776/322-ignore_broken_bssid.patch b/package/madwifi/patches-r3776/322-ignore_broken_bssid.patch
deleted file mode 100644
index 0bae461f6..000000000
--- a/package/madwifi/patches-r3776/322-ignore_broken_bssid.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-Some misconfigured APs broadcast NULL BSSIDs, which can confuse the STA
-Ignore those when scanning.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_scan_sta.c
-+++ b/net80211/ieee80211_scan_sta.c
-@@ -242,6 +242,10 @@
- 	struct ieee80211_scan_entry *ise;
- 	int hash;
- 
-+	/* workaround for broken APs that broadcast NULL BSSIDs */
-+	if (memcmp(wh->i_addr3, "\x00\x00\x00\x00\x00\x00", 6) == 0)
-+		return 0;
-+
- 	hash = STA_HASH(macaddr);
- 	SCAN_STA_LOCK_IRQ(st);
- 	LIST_FOREACH(se, &st->st_hash[hash], se_hash)
diff --git a/package/madwifi/patches-r3776/323-crash_fix.patch b/package/madwifi/patches-r3776/323-crash_fix.patch
deleted file mode 100644
index 2da3bf352..000000000
--- a/package/madwifi/patches-r3776/323-crash_fix.patch
+++ /dev/null
@@ -1,21 +0,0 @@
---- a/net80211/ieee80211_node.c
-+++ b/net80211/ieee80211_node.c
-@@ -1999,11 +1999,13 @@
- 	/* From this point onwards we can no longer find the node,
- 	 * so no more references are generated
- 	 */
--	ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
--	ieee80211_del_wds_node(nt, ni);
--	IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
--	node_table_leave_locked(nt, ni);
--	IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
-+	if (nt) {
-+		ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
-+		ieee80211_del_wds_node(nt, ni);
-+		IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
-+		node_table_leave_locked(nt, ni);
-+		IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
-+	}
- 
- 	/*
- 	 * If node wasn't previously associated all
diff --git a/package/madwifi/patches-r3776/324-reassoc.patch b/package/madwifi/patches-r3776/324-reassoc.patch
deleted file mode 100644
index 7d1ade3dd..000000000
--- a/package/madwifi/patches-r3776/324-reassoc.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-Add a preliminary fix for the reassoc check, but disable reassoc entirely for now
-until we've figured out why it fails frequently.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_node.c
-+++ b/net80211/ieee80211_node.c
-@@ -561,10 +561,9 @@
- EXPORT_SYMBOL(ieee80211_ibss_merge);
- 
- static __inline int
--ssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
-+bssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
- {
--	return (a->ni_esslen == b->ni_esslen &&
--		memcmp(a->ni_essid, b->ni_essid, a->ni_esslen) == 0);
-+	return (memcmp(a->ni_bssid, b->ni_bssid, IEEE80211_ADDR_LEN) == 0);
- }
- 
- /*
-@@ -596,8 +595,8 @@
- 	 * Check if old+new node have the same ssid in which
- 	 * case we can reassociate when operating in sta mode.
- 	 */
--	canreassoc = ((obss != NULL) &&
--		(vap->iv_state == IEEE80211_S_RUN) && ssid_equal(obss, selbs));
-+	canreassoc = 0; /* ((obss != NULL) &&
-+		(vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
- 	vap->iv_bss = selbs;
- 	IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
- 	if (obss != NULL)
diff --git a/package/madwifi/patches-r3776/325-sta_node_leave.patch b/package/madwifi/patches-r3776/325-sta_node_leave.patch
deleted file mode 100644
index 6b0dcb8e8..000000000
--- a/package/madwifi/patches-r3776/325-sta_node_leave.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-Drop stale AP nodes from the client list when disconnecting.
-Fixes some reassoc issues.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_proto.c
-+++ b/net80211/ieee80211_proto.c
-@@ -1352,7 +1352,7 @@
- 				IEEE80211_SEND_MGMT(ni,
- 					IEEE80211_FC0_SUBTYPE_DISASSOC,
- 					IEEE80211_REASON_ASSOC_LEAVE);
--				ieee80211_sta_leave(ni);
-+				ieee80211_node_leave(ni);
- 				break;
- 			case IEEE80211_M_HOSTAP:
- 				ieee80211_iterate_nodes(&ic->ic_sta,
-@@ -1362,6 +1362,7 @@
- 				break;
- 			}
- 			goto reset;
-+		case IEEE80211_S_AUTH:
- 		case IEEE80211_S_ASSOC:
- 			switch (vap->iv_opmode) {
- 			case IEEE80211_M_STA:
-@@ -1380,7 +1381,6 @@
- 		case IEEE80211_S_SCAN:
- 			ieee80211_cancel_scan(vap);
- 			goto reset;
--		case IEEE80211_S_AUTH:
- 		reset:
- 			ieee80211_reset_bss(vap);
- 			break;
-@@ -1436,7 +1436,7 @@
- 			break;
- 		case IEEE80211_S_RUN:		/* beacon miss */
- 			if (vap->iv_opmode == IEEE80211_M_STA) {
--				ieee80211_sta_leave(ni);
-+				ieee80211_node_leave(ni);
- 				vap->iv_flags &= ~IEEE80211_F_SIBSS;	/* XXX */
- 				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
- 					ieee80211_check_scan(vap,
-@@ -1487,7 +1487,7 @@
- 				vap->iv_state = ostate;	/* stay RUN */
- 				break;
- 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
--				ieee80211_sta_leave(ni);
-+				ieee80211_node_leave(ni);
- 				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
- 					/* try to reauth */
- 					IEEE80211_SEND_MGMT(ni,
-@@ -1514,7 +1514,7 @@
- 				IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
- 			break;
- 		case IEEE80211_S_RUN:
--			ieee80211_sta_leave(ni);
-+			ieee80211_node_leave(ni);
- 			if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
- 				/* NB: caller specifies ASSOC/REASSOC by arg */
- 				IEEE80211_SEND_MGMT(ni, arg ?
diff --git a/package/madwifi/patches-r3776/326-bmiss_handling.patch b/package/madwifi/patches-r3776/326-bmiss_handling.patch
deleted file mode 100644
index 0c7263050..000000000
--- a/package/madwifi/patches-r3776/326-bmiss_handling.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-Improve the beacon miss handling. Instead of just dropping the connection,
-send a directed probe request to the AP to see if it's still responding.
-Schedule a software beacon miss timer in this case, which adds a timeout
-for the APs probe response.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -3369,12 +3369,17 @@
- 			}
- 
- 			/* WDS/Repeater: re-schedule software beacon timer for 
--			 * STA. */
--			if ((vap->iv_state == IEEE80211_S_RUN) &&
--			    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
--				mod_timer(&vap->iv_swbmiss, 
-+			 * STA. Reset consecutive bmiss counter as well */
-+			IEEE80211_LOCK_IRQ(ic);
-+			if (vap->iv_state == IEEE80211_S_RUN) {
-+				vap->iv_bmiss_count = 0;
-+				if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
-+					mod_timer(&vap->iv_swbmiss,
- 						jiffies + vap->iv_swbmiss_period);
-+				else
-+					del_timer(&vap->iv_swbmiss);
- 			}
-+			IEEE80211_UNLOCK_IRQ(ic);
- 
- 			/* If scanning, pass the info to the scan module.
- 			 * Otherwise, check if it's the right time to do
---- a/net80211/ieee80211_proto.c
-+++ b/net80211/ieee80211_proto.c
-@@ -1213,6 +1213,8 @@
- 	}
- 	/* XXX locking */
- 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
-+		int count;
-+
- 		IEEE80211_DPRINTF(vap,
- 			IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
- 			"%s\n", "beacon miss");
-@@ -1225,6 +1227,29 @@
- 		if (vap->iv_opmode != IEEE80211_M_STA ||
- 		    vap->iv_state != IEEE80211_S_RUN)
- 			continue;
-+
-+		IEEE80211_LOCK_IRQ(ic);
-+		count = vap->iv_bmiss_count++;
-+		if (count) {
-+			/* if the counter was already above zero, reset it
-+			 * here, since we're going to do the bmiss handling
-+			 * in any case */
-+			vap->iv_bmiss_count = 0;
-+		} else {
-+			/* schedule the software beacon miss timer, it will be
-+			 * cancelled, if the probe request is acked */
-+			mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
-+		}
-+		IEEE80211_UNLOCK_IRQ(ic);
-+
-+		if (!count) {
-+			ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
-+				vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
-+				vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen,
-+				NULL, 0);
-+			continue;
-+		}
-+
- 		if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
- #ifdef ATH_SUPERG_DYNTURBO
- 			/* 
-@@ -1621,14 +1646,14 @@
- 		}
- 
- 		/* WDS/Repeater: Start software beacon timer for STA */
-+		vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
-+		vap->iv_swbmiss.data = (unsigned long) vap;
-+		vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
-+			vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
-+
- 		if (ostate != IEEE80211_S_RUN &&
- 		    (vap->iv_opmode == IEEE80211_M_STA &&
- 		     vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
--			vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
--			vap->iv_swbmiss.data = (unsigned long) vap;
--			vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
--				vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
--
- 			mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
- 		}
- 
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -292,6 +292,7 @@
- 
- 	struct timer_list iv_swbmiss;			/* software beacon miss timer */
- 	u_int16_t iv_swbmiss_period; 			/* software beacon miss timer period */
-+	u_int16_t iv_bmiss_count;			/* consecutive beacon miss counter */
- 	struct ieee80211_nsparams iv_nsparams;		/* new state parameters for tasklet for stajoin1 */
- 	struct IEEE80211_TQ_STRUCT iv_stajoin1tq; 	/* tasklet for newstate action called from stajoin1tq */
- 	unsigned int iv_nsdone;				/* Done with scheduled newstate tasklet */
diff --git a/package/madwifi/patches-r3776/327-rssi_disconnect.patch b/package/madwifi/patches-r3776/327-rssi_disconnect.patch
deleted file mode 100644
index b7e406cb0..000000000
--- a/package/madwifi/patches-r3776/327-rssi_disconnect.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-Add an optional threshold for low-rssi disconnection. This can be useful
-when letting wpa_supplicant control roaming.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/net80211/ieee80211_ioctl.h
-+++ b/net80211/ieee80211_ioctl.h
-@@ -656,6 +656,8 @@
- 	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
- 	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
- 	IEEE80211_PARAM_BGSCAN_THRESH		= 87,	/* bg scan rssi threshold */
-+	IEEE80211_PARAM_RSSI_DIS_THR	= 88,	/* rssi threshold for disconnection */
-+	IEEE80211_PARAM_RSSI_DIS_COUNT	= 89,	/* counter for rssi threshold */
- };
- 
- #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
---- a/net80211/ieee80211_wireless.c
-+++ b/net80211/ieee80211_wireless.c
-@@ -2832,6 +2832,12 @@
- 	case IEEE80211_PARAM_ROAM_RATE_11G:
- 		vap->iv_roam.rate11g = value;
- 		break;
-+	case IEEE80211_PARAM_RSSI_DIS_THR:
-+		vap->iv_rssi_dis_thr = value;
-+		break;
-+	case IEEE80211_PARAM_RSSI_DIS_COUNT:
-+		vap->iv_rssi_dis_max = value;
-+		break;
- 	case IEEE80211_PARAM_UAPSDINFO:
- 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
- 			if (ic->ic_caps & IEEE80211_C_UAPSD) {
-@@ -3220,6 +3226,12 @@
- 	case IEEE80211_PARAM_ROAM_RATE_11G:
- 		param[0] = vap->iv_roam.rate11g;
- 		break;
-+	case IEEE80211_PARAM_RSSI_DIS_THR:
-+		param[0] = vap->iv_rssi_dis_thr;
-+		break;
-+	case IEEE80211_PARAM_RSSI_DIS_COUNT:
-+		param[0] = vap->iv_rssi_dis_max;
-+		break;
- 	case IEEE80211_PARAM_UAPSDINFO:
- 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
- 			if (IEEE80211_VAP_UAPSD_ENABLED(vap))
-@@ -5770,6 +5782,14 @@
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rate11g_x2" },
- 	{ IEEE80211_PARAM_ROAM_RATE_11G,
- 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rate11g_x2" },
-+	{ IEEE80211_PARAM_RSSI_DIS_THR,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_disthr" },
-+	{ IEEE80211_PARAM_RSSI_DIS_THR,
-+	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_disthr" },
-+	{ IEEE80211_PARAM_RSSI_DIS_COUNT,
-+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_discnt" },
-+	{ IEEE80211_PARAM_RSSI_DIS_COUNT,
-+	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_discnt" },
- 	{ IEEE80211_PARAM_UAPSDINFO,
- 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "uapsd" },
- 	{ IEEE80211_PARAM_UAPSDINFO,
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -3234,6 +3234,17 @@
- 
- 			/* When rssi is low, start doing bgscans more frequently to allow
- 			 * the supplicant to make a better switching decision */
-+			if ((vap->iv_rssi_dis_thr > 0) && (vap->iv_rssi_dis_max > 0)) {
-+				if ((rssi > 0) && (rssi < vap->iv_rssi_dis_thr)) {
-+					if (++vap->iv_rssi_dis_trig > vap->iv_rssi_dis_max) {
-+						vap->iv_rssi_dis_trig = 0;
-+						ieee80211_node_leave(ni);
-+						return 0;
-+					}
-+				} else {
-+					vap->iv_rssi_dis_trig = 0;
-+				}
-+			}
- 			if ((rssi < vap->iv_bgscanthr) &&
- 					(!vap->iv_bgscanthr_next ||
- 						!time_before(jiffies, vap->iv_bgscanthr_next)) &&
---- a/net80211/ieee80211_var.h
-+++ b/net80211/ieee80211_var.h
-@@ -233,6 +233,9 @@
- 	u_int iv_bgscanintvl;				/* bg scan min interval */
- 	u_int iv_bgscanthr;					/* bg scan rssi threshold */
- 	u_int iv_bgscantrintvl;				/* bg scan trigger interval */
-+	u_int iv_rssi_dis_thr;				/* rssi disassoc threshold */
-+	u_int iv_rssi_dis_max;				/* max beacons below disconnect threshold */
-+	u_int iv_rssi_dis_trig;				/* rssi disassoc trigger count */
- 	unsigned long iv_bgscanthr_next;		/* last trigger for bgscan */
- 	u_int iv_scanvalid;				/* scan cache valid threshold */
- 	struct ieee80211_roam iv_roam;			/* sta-mode roaming state */
diff --git a/package/madwifi/patches-r3776/328-memory_alloc.patch b/package/madwifi/patches-r3776/328-memory_alloc.patch
deleted file mode 100644
index ff60dbdb3..000000000
--- a/package/madwifi/patches-r3776/328-memory_alloc.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -504,7 +504,7 @@
- 
- 	/* Allocate space for dynamically determined maximum VAP count */
- 	sc->sc_bslot = 
--		kzalloc(ath_maxvaps * sizeof(struct ieee80211vap), GFP_KERNEL);
-+		kzalloc(ath_maxvaps * sizeof(struct ieee80211vap *), GFP_KERNEL);
- 
- 	/*
- 	 * Cache line size is used to size and align various
diff --git a/package/madwifi/patches-r3776/329-turbo_chansearch.patch b/package/madwifi/patches-r3776/329-turbo_chansearch.patch
deleted file mode 100644
index ba8b01c12..000000000
--- a/package/madwifi/patches-r3776/329-turbo_chansearch.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/net80211/ieee80211.c
-+++ b/net80211/ieee80211.c
-@@ -695,6 +695,7 @@
- 	int i;
- 
- 	/* Brute force search */
-+	flags &= IEEE80211_CHAN_ALLTURBO;
- 	for (i = 0; i < ic->ic_nchans; i++) {
- 		c = &ic->ic_channels[i];
- 		if (c->ic_freq == freq &&
diff --git a/package/madwifi/patches-r3776/330-bstuck_thresh.patch b/package/madwifi/patches-r3776/330-bstuck_thresh.patch
deleted file mode 100644
index 5f864bb59..000000000
--- a/package/madwifi/patches-r3776/330-bstuck_thresh.patch
+++ /dev/null
@@ -1,52 +0,0 @@
---- a/ath/if_ath.c
-+++ b/ath/if_ath.c
-@@ -354,6 +354,7 @@
- static int ath_outdoor = AH_FALSE;		/* enable outdoor use */
- static int ath_xchanmode = AH_TRUE;		/* enable extended channels */
- static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
-+static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
- static char *autocreate = "sta";
- static char *ratectl = DEF_RATE_CTL;
- static int rfkill = 0;
-@@ -397,6 +398,7 @@
- #ifdef ATH_CAP_TPC
- MODULE_PARM(hal_tpc, "i");
- #endif
-+MODULE_PARM(bstuck_thresh, "i");
- MODULE_PARM(autocreate, "s");
- MODULE_PARM(ratectl, "s");
- #else
-@@ -410,6 +412,7 @@
- #ifdef ATH_CAP_TPC
- module_param(hal_tpc, int, 0600);
- #endif
-+module_param(bstuck_thresh, int, 0600);
- module_param(autocreate, charp, 0600);
- module_param(ratectl, charp, 0600);
- #endif
-@@ -422,6 +425,7 @@
- MODULE_PARM_DESC(hal_tpc, "Disables manual per-packet transmit power control and "
- 		"lets this be managed by the HAL.  Default is OFF.");
- #endif
-+MODULE_PARM_DESC(bstuck_thresh, "Override default stuck beacon threshold");
- MODULE_PARM_DESC(autocreate, "Create ath device in "
- 		"[sta|ap|wds|adhoc|ahdemo|monitor] mode. defaults to sta, use "
- 		"'none' to disable");
-@@ -5239,7 +5243,7 @@
- 		DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
- 			"Missed %u consecutive beacons (n_beacon=%u)\n",
- 			sc->sc_bmisscount, n_beacon);
--		if (sc->sc_bmisscount > BSTUCK_THRESH)
-+		if (sc->sc_bmisscount > bstuck_thresh)
- 			ATH_SCHEDULE_TQUEUE(&sc->sc_bstucktq, needmark);
- 		return;
- 	}
-@@ -5410,7 +5414,7 @@
- 	 *     check will be true, in which case return
- 	 *     without resetting the driver.
- 	 */
--	if (sc->sc_bmisscount <= BSTUCK_THRESH)
-+	if (sc->sc_bmisscount <= bstuck_thresh)
- 		return;
- 	EPRINTF(sc, "Stuck beacon; resetting (beacon miss count: %u)\n",
- 		sc->sc_bmisscount);
diff --git a/package/madwifi/patches-r3776/331-linux24_fix.patch b/package/madwifi/patches-r3776/331-linux24_fix.patch
deleted file mode 100644
index 1d9a2d06c..000000000
--- a/package/madwifi/patches-r3776/331-linux24_fix.patch
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/ath_hal/Makefile
-+++ b/ath_hal/Makefile
-@@ -79,10 +79,11 @@
- quiet_cmd_uudecode = UUDECODE $@
-       cmd_uudecode = $(obj)/uudecode -o $@ $<
- 
--$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
- ifdef LINUX24
-+$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
- 	$(Q)$(obj)/uudecode -o $@ $<
- else
-+$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
- 	$(call if_changed,uudecode)
- endif
- # Replace as many hashed names as possible with meaningful
diff --git a/package/madwifi/patches-r3776/332-retransmit_check.patch b/package/madwifi/patches-r3776/332-retransmit_check.patch
deleted file mode 100644
index ec1fcf9c7..000000000
--- a/package/madwifi/patches-r3776/332-retransmit_check.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/net80211/ieee80211.h
-+++ b/net80211/ieee80211.h
-@@ -174,8 +174,6 @@
- #define	IEEE80211_SEQ_SEQ_MASK			0xfff0
- #define	IEEE80211_SEQ_SEQ_SHIFT			4
- 
--#define	IEEE80211_SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
--
- #define	IEEE80211_NWID_LEN			32
- 
- #define	IEEE80211_QOS_TXOP			0x00ff
---- a/net80211/ieee80211_input.c
-+++ b/net80211/ieee80211_input.c
-@@ -406,7 +406,7 @@
- 				tid = 0;
- 			rxseq = le16toh(*(__le16 *)wh->i_seq);
- 			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
--			    IEEE80211_SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
-+			    (rxseq == ni->ni_rxseqs[tid])) {
- 				/* duplicate, discard */
- 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
- 					bssid, "duplicate",
diff --git a/package/madwifi/patches-r3776/333-hal_init_msg.patch b/package/madwifi/patches-r3776/333-hal_init_msg.patch
deleted file mode 100644
index 1369dcfc1..000000000
--- a/package/madwifi/patches-r3776/333-hal_init_msg.patch
+++ /dev/null
@@ -1,30 +0,0 @@
---- a/ath_hal/ah_os.c
-+++ b/ath_hal/ah_os.c
-@@ -1136,9 +1136,6 @@
-  * Module glue.
-  */
- #include "version.h"
--#if 0
--static char *dev_info = "ath_hal";
--#endif
- 
- MODULE_AUTHOR("Errno Consulting, Sam Leffler");
- MODULE_DESCRIPTION("Atheros Hardware Access Layer (HAL)");
-@@ -1172,7 +1169,7 @@
- static int __init
- init_ath_hal(void)
- {
--	const char *sep;
-+	const char *sep = "";
- 	int i;
- #ifdef MMIOTRACE
- 	kmmio_logmsg = _kmmio_logmsg;
-@@ -1181,7 +1178,7 @@
- 	ifxmips_emulate = ifxmips_has_brn_block();
- #endif
- 
--	sep = "";
-+	printk(KERN_INFO "hal: %s (", ath_hal_version);
- 	for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
- 		printk("%s%s", sep, ath_hal_buildopts[i]);
- 		sep = ", ";
diff --git a/package/madwifi/patches-testing/102-multicall_binary.patch b/package/madwifi/patches-testing/102-multicall_binary.patch
new file mode 100644
index 000000000..7ddd45632
--- /dev/null
+++ b/package/madwifi/patches-testing/102-multicall_binary.patch
@@ -0,0 +1,359 @@
+--- a/tools/80211debug.c
++++ b/tools/80211debug.c
+@@ -48,6 +48,7 @@
+ #include <ctype.h>
+ #include <getopt.h>
+ #include <err.h>
++#include "do_multi.h"
+ 
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -185,7 +186,7 @@
+ #endif /* __linux__ */
+ 
+ int
+-main(int argc, char *argv[])
++CMD(a80211debug)(int argc, char *argv[])
+ {
+ 	const char *ifname = "ath0";
+ 	const char *cp, *tp;
+--- a/tools/80211stats.c
++++ b/tools/80211stats.c
+@@ -59,6 +59,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ 
+ #ifndef SIOCG80211STATS
+ #define	SIOCG80211STATS	(SIOCDEVPRIVATE + 2)
+@@ -241,7 +242,7 @@
+ }
+ 
+ int
+-main(int argc, char *argv[])
++CMD(a80211stats)(int argc, char *argv[])
+ {
+ 	int c, len;
+ 	struct ieee80211req_sta_info *si;
+--- a/tools/athchans.c
++++ b/tools/athchans.c
+@@ -58,6 +58,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ 
+ static	int s = -1;
+ static const char *progname;
+@@ -140,8 +141,9 @@
+ }
+ 
+ #define	MAXCHAN	((int)(sizeof(struct ieee80211req_chanlist) * NBBY))
++
+ int
+-main(int argc, char *argv[])
++CMD(athchans)(int argc, char *argv[])
+ {
+ 	const char *ifname = "wifi0";
+ 	struct ieee80211req_chanlist chanlist;
+--- a/tools/athctrl.c
++++ b/tools/athctrl.c
+@@ -52,6 +52,7 @@
+ #include <err.h>
+ 
+ #include <net/if.h>
++#include "do_multi.h"
+ 
+ static int
+ setsysctrl(const char *dev, const char *control , u_long value)
+@@ -88,7 +89,7 @@
+ }
+ 
+ int
+-main(int argc, char *argv[])
++CMD(athctrl)(int argc, char *argv[])
+ {
+ 	char device[IFNAMSIZ + 1];
+ 	int distance = -1;
+--- a/tools/athdebug.c
++++ b/tools/athdebug.c
+@@ -51,6 +51,7 @@
+ #include <ctype.h>
+ #include <getopt.h>
+ #include <err.h>
++#include "do_multi.h"
+ 
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -194,7 +195,7 @@
+ #endif /* __linux__ */
+ 
+ int
+-main(int argc, char *argv[])
++CMD(athdebug)(int argc, char *argv[])
+ {
+ #ifdef __linux__
+ 	const char *ifname = "wifi0";
+--- a/tools/athkey.c
++++ b/tools/athkey.c
+@@ -58,6 +58,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ 
+ static int s = -1;
+ static const char *progname;
+@@ -213,8 +214,7 @@
+ 	exit(-1);
+ }
+ 
+-int
+-main(int argc, char *argv[])
++int CMD(athkey)(int argc, char *argv[])
+ {
+ 	const char *ifname = "wifi0";
+ 	struct ieee80211req_key setkey;
+--- a/tools/athstats.c
++++ b/tools/athstats.c
+@@ -65,6 +65,7 @@
+ 
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
++#include "do_multi.h"
+ 
+ static const struct {
+ 	u_int		phyerr;
+@@ -228,7 +229,7 @@
+ }
+ 
+ int
+-main(int argc, char *argv[])
++CMD(athstats)(int argc, char *argv[])
+ {
+ #ifdef __linux__
+ 	const char *ifname = "wifi0";
+--- /dev/null
++++ b/tools/do_multi.c
+@@ -0,0 +1,36 @@
++#include <string.h>
++#include "do_multi.h"
++
++int
++main(int argc, char *argv[])
++{
++    char *progname;
++    int ret = 0;
++
++    progname = basename(argv[0]);
++
++    if(strcmp(progname, "80211debug") == 0)
++	ret = a80211debug_init(argc, argv);
++    if(strcmp(progname, "80211stats") == 0)
++	ret = a80211stats_init(argc, argv);
++    if(strcmp(progname, "athchans") == 0)
++	ret = athchans_init(argc, argv);
++    if(strcmp(progname, "athctrl") == 0)
++	ret =  athctrl_init(argc, argv);
++    if(strcmp(progname, "athdebug") == 0)
++	ret =  athdebug_init(argc, argv);
++    if(strcmp(progname, "athkey") == 0)
++	ret =  athkey_init(argc, argv);
++    if(strcmp(progname, "athstats") == 0)
++	ret =  athstats_init(argc, argv);
++    if(strcmp(progname, "wlanconfig") == 0)
++	ret =  wlanconfig_init(argc, argv);
++    if(strcmp(progname, "wpakey") == 0)
++	ret =  wpakey_init(argc, argv);
++    if(strcmp(progname, "athchans") == 0)
++	ret =  athchans_init(argc, argv);
++    if(strcmp(progname, "ath_info") == 0)
++	ret =  athinfo_init(argc, argv);
++
++    return ret;
++}
+--- /dev/null
++++ b/tools/do_multi.h
+@@ -0,0 +1,15 @@
++#ifdef DO_MULTI
++int a80211debug_init(int argc, char *argv[]);
++int a80211stats_init(int argc, char *argv[]);
++int athchans_init(int argc, char *argv[]);
++int athctrl_init(int argc, char *argv[]);
++int athdebug_init(int argc, char *argv[]);
++int athkey_init(int argc, char *argv[]);
++int athstats_init(int argc, char *argv[]);
++int wlanconfig_init(int argc, char *argv[]);
++int athinfo_init(int argc, char *argv[]);
++
++#define CMD(name) name##_init
++#else
++#define CMD(name) main
++#endif
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -50,42 +50,43 @@
+ PROGRAMS = athstats 80211stats athkey athchans athctrl \
+ 	athdebug 80211debug wlanconfig wpakey
+ 
++OBJS = $(patsubst %,%.o,$(PROGRAMS)) ath_info/ath_info.o
+ SUBDIRS = ath_info
+ 
+-INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL)
++INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
+ CFLAGS = -g -O2 -Wall
+ ALL_CFLAGS = $(CFLAGS) $(INCS)
+ LDFLAGS =
+ 
+-all: all-subdirs $(PROGRAMS)
++all: all-subdirs compile
+ 
+ all-subdirs:
+ 	for d in $(SUBDIRS); do \
+ 		$(MAKE) -C $$d || exit 1; \
+ 	done
+ 
+-athstats: athstats.c
+-	$(CC) -o athstats $(ALL_CFLAGS) -I$(TOP)/ath $(LDFLAGS) athstats.c
+-80211stats: 80211stats.c
+-	$(CC) -o 80211stats $(ALL_CFLAGS) $(LDFLAGS) 80211stats.c
+-athkey: athkey.c
+-	$(CC) -o athkey $(ALL_CFLAGS) $(LDFLAGS) athkey.c
+-athchans: athchans.c
+-	$(CC) -o athchans $(ALL_CFLAGS) $(LDFLAGS) athchans.c
+-athctrl: athctrl.c
+-	$(CC) -o athctrl $(ALL_CFLAGS) $(LDFLAGS) athctrl.c
+-athdebug: athdebug.c
+-	$(CC) -o athdebug $(ALL_CFLAGS) $(LDFLAGS) athdebug.c
+-wlanconfig: wlanconfig.c
+-	$(CC) -o wlanconfig $(ALL_CFLAGS) $(LDFLAGS) wlanconfig.c
+-80211debug: 80211debug.c
+-	$(CC) -o 80211debug $(ALL_CFLAGS) $(LDFLAGS) 80211debug.c
+-wpakey: wpakey.c
+-	$(CC) -o wpakey $(ALL_CFLAGS) $(LDFLAGS) wpakey.c
++%.o: %.c
++	${CC} $(ALL_CFLAGS) -c -o $@  $<
++
++ifneq ($(DO_MULTI),)
++ALL_CFLAGS += -DDO_MULTI=1
++madwifi_multi: $(OBJS) do_multi.o
++	$(CC) $(LDFLAGS) -o $@ $^
++
++compile: madwifi_multi
++	for i in $(PROGRAMS); do \
++		ln -sf madwifi_multi $$i; \
++	done
++else
++$(PROGRAMS):
++	$(CC) $(ALL_CFLAGS) -o $@ $@.c
++
++compile: $(PROGRAMS)
++endif
+ 
+ install: all
+ 	install -d $(DESTDIR)$(BINDIR)
+-	for i in $(PROGRAMS); do \
++	for i in $(PROGRAMS) $(if $(DO_MULTI),madwifi_multi); do \
+ 		install $$i $(DESTDIR)$(BINDIR)/$$i; \
+ 		$(STRIP) $(DESTDIR)$(BINDIR)/$$i; \
+ 	done
+@@ -97,7 +98,7 @@
+ 	done
+ 
+ uninstall:
+-	for i in $(PROGRAMS); do \
++	for i in $(PROGRAMS) $(if $(DO_MULTI),madwifi_multi); do \
+ 		rm -f $(DESTDIR)$(BINDIR)/$$i; \
+ 	done
+ 	for i in $(PROGRAMS:=.8); do \
+@@ -108,7 +109,7 @@
+ 	done
+ 
+ clean:
+-	rm -f $(PROGRAMS) core a.out
++	rm -f $(if $(DO_MULTI), madwifi_multi) $(PROGRAMS) core a.out *.o
+ 	for d in $(SUBDIRS); do \
+ 		$(MAKE) -C $$d clean; \
+ 	done
+--- a/tools/wlanconfig.c
++++ b/tools/wlanconfig.c
+@@ -61,6 +61,7 @@
+ #include "net80211/ieee80211.h"
+ #include "net80211/ieee80211_crypto.h"
+ #include "net80211/ieee80211_ioctl.h"
++#include "do_multi.h"
+ 
+ /*
+  * These are taken from ieee80211_node.h
+@@ -100,7 +101,7 @@
+ static int verbose = 0;
+ 
+ int
+-main(int argc, char *argv[])
++CMD(wlanconfig)(int argc, char *argv[])
+ {
+ 	const char *ifname, *cmd;
+ 	unsigned char bnounit = 0;
+--- a/tools/ath_info/Makefile
++++ b/tools/ath_info/Makefile
+@@ -17,11 +17,18 @@
+ 
+ all: $(PROGRAMS)
+ 
++
++ifneq ($(DO_MULTI),)
++ath_info: ath_info.o
++	rm -f $@
++	ln -s ../madwifi_multi $@
++else
+ ath_info: ath_info.o
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
++endif
+ 
+ .c.o:
+-	$(CC) $(CFLAGS) -c $<
++	$(CC) $(CFLAGS) $(if $(DO_MULTI),-DDO_MULTI=1 -I..) -c $<
+ 
+ clean:
+ 	rm -f *.o $(PROGRAMS)
+--- a/tools/ath_info/ath_info.c
++++ b/tools/ath_info/ath_info.c
+@@ -28,6 +28,7 @@
+ #include <sys/mman.h>
+ #include <endian.h>
+ #include <byteswap.h>
++#include "do_multi.h"
+ 
+ #undef ARRAY_SIZE
+ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+@@ -1982,7 +1983,8 @@
+ 	printf("\n");
+ }
+ 
+-int main(int argc, char *argv[])
++int
++CMD(athinfo)(int argc, char *argv[])
+ {
+ 	unsigned long long dev_addr;
+ 	u_int16_t srev, phy_rev_5ghz, phy_rev_2ghz, ee_magic;
+--- a/tools/wpakey.c
++++ b/tools/wpakey.c
+@@ -25,6 +25,7 @@
+ 
+ #include <unistd.h>
+ #include <sys/ioctl.h>
++#include "do_multi.h"
+ 
+ #define MACS "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
+ #define MACP(mac) (mac)[0], (mac)[1], (mac)[2], (mac)[3], (mac)[4], (mac)[5]
+@@ -234,7 +235,8 @@
+ 		"", dev);
+ }
+ 
+-int main(int argc, char** argv) {
++int
++CMD(wpakey)(int argc, char** argv) {
+ 	int keyidx = 0;
+ 	uint8_t mac[6];
+ 	int cipher = IEEE80211_CIPHER_AES_CCM;
diff --git a/package/madwifi/patches-testing/104-autocreate_none.patch b/package/madwifi/patches-testing/104-autocreate_none.patch
new file mode 100644
index 000000000..16ce6e863
--- /dev/null
+++ b/package/madwifi/patches-testing/104-autocreate_none.patch
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -482,7 +482,7 @@
+ 	HAL_STATUS status;
+ 	int error = 0;
+ 	unsigned int i;
+-	int autocreatemode = IEEE80211_M_STA;
++	int autocreatemode = -1;
+ 	u_int8_t csz;
+ 
+ 	sc->devid = devid;
diff --git a/package/madwifi/patches-testing/105-ratectl_attach.patch b/package/madwifi/patches-testing/105-ratectl_attach.patch
new file mode 100644
index 000000000..79b08dfb8
--- /dev/null
+++ b/package/madwifi/patches-testing/105-ratectl_attach.patch
@@ -0,0 +1,23 @@
+--- a/net80211/ieee80211_rate.c
++++ b/net80211/ieee80211_rate.c
+@@ -100,8 +100,18 @@
+ 		ieee80211_load_module(buf);
+ 
+ 	if (!ratectls[id].attach) {
+-		printk(KERN_ERR "Error loading module \"%s\"\n", buf);
+-		return NULL;
++		/* pick the first available rate control module */
++		printk(KERN_INFO "Rate control module \"%s\" not available\n", buf);
++		for (id = 0; id < IEEE80211_RATE_MAX; id++) {
++			if (ratectls[id].attach)
++				break;
++		}
++		if (!ratectls[id].attach) {
++			printk(KERN_ERR "No rate control module available");
++			return NULL;
++		} else {
++			printk(KERN_INFO "Using \"%s\" instead.\n", module_names[id]);
++		}
+ 	}
+ 
+ 	ctl = ratectls[id].attach(sc);
diff --git a/package/madwifi/patches-testing/111-minstrel_crash.patch b/package/madwifi/patches-testing/111-minstrel_crash.patch
new file mode 100644
index 000000000..dd96c4e60
--- /dev/null
+++ b/package/madwifi/patches-testing/111-minstrel_crash.patch
@@ -0,0 +1,12 @@
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -415,6 +415,9 @@
+ 			return;
+ 		}
+ 
++		if (sn->num_rates <= 0)
++			return;
++
+ 		if (sn->is_sampling) {
+ 			sn->is_sampling = 0;
+ 			if (sn->rs_sample_rate_slower)
diff --git a/package/madwifi/patches-testing/122-replayfail_workaround.patch b/package/madwifi/patches-testing/122-replayfail_workaround.patch
new file mode 100644
index 000000000..de5a8f316
--- /dev/null
+++ b/package/madwifi/patches-testing/122-replayfail_workaround.patch
@@ -0,0 +1,12 @@
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -330,6 +330,9 @@
+ 		k->wk_cipher->ic_name, k->wk_keyix,
+ 		(unsigned long long)rsc);
+ 
++	/* disabled for now due to bogus events for unknown reasons */
++	return;
++
+ 	/* TODO: needed parameters: count, keyid, key type, src address, TSC */
+ 	snprintf(buf, sizeof(buf), "%s(keyid=%d %scast addr=" MAC_FMT ")", tag,
+ 		k->wk_keyix,
diff --git a/package/madwifi/patches-testing/123-ccmp_checks.patch b/package/madwifi/patches-testing/123-ccmp_checks.patch
new file mode 100644
index 000000000..6db9c2d78
--- /dev/null
+++ b/package/madwifi/patches-testing/123-ccmp_checks.patch
@@ -0,0 +1,22 @@
+--- a/net80211/ieee80211_crypto_ccmp.c
++++ b/net80211/ieee80211_crypto_ccmp.c
+@@ -478,6 +478,9 @@
+ 	uint8_t *mic, *pos;
+ 	u_int space;
+ 
++	if (ctx->cc_tfm == NULL)
++		return 0;
++
+ 	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
+ 
+ 	skb = skb0;
+@@ -592,6 +595,9 @@
+ 	uint8_t *pos, *mic;
+ 	u_int space;
+ 
++	if (ctx->cc_tfm == NULL)
++		return 0;
++
+ 	ctx->cc_vap->iv_stats.is_crypto_ccmp++;
+ 
+ 	skb = skb0;
diff --git a/package/madwifi/patches-testing/124-linux24_compat.patch b/package/madwifi/patches-testing/124-linux24_compat.patch
new file mode 100644
index 000000000..2ab9364b9
--- /dev/null
+++ b/package/madwifi/patches-testing/124-linux24_compat.patch
@@ -0,0 +1,202 @@
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -129,6 +129,11 @@
+ #define ATH_GET_NETDEV_DEV(ndev)	((ndev)->class_dev.dev)
+ #endif
+ 
++#ifndef NETDEV_TX_OK
++#define NETDEV_TX_OK    0
++#define NETDEV_TX_BUSY  1
++#endif
++
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
+ static inline struct net_device *_alloc_netdev(int sizeof_priv, const char *mask,
+ 					       void (*setup)(struct net_device *))
+--- a/ath/if_ath_radar.c
++++ b/ath/if_ath_radar.c
+@@ -89,6 +89,13 @@
+ #define nofloat_pct(_value, _pct) \
+ 	( (_value * (1000 + _pct)) / 1000 )
+ 
++#ifndef list_for_each_entry_reverse
++#define list_for_each_entry_reverse(pos, head, member)			\
++	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
++	     prefetch(pos->member.prev), &pos->member != (head); 	\
++	     pos = list_entry(pos->member.prev, typeof(*pos), member))
++#endif
++
+ struct radar_pattern_specification {
+ 	/* The name of the rule/specification (i.e. what did we detect) */
+ 	const char *name;
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4878,6 +4878,46 @@
+ 	return (txqs & (1 << qnum));
+ }
+ 
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
++static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
++{
++	int ret;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	ret = v->counter;
++	if (likely(ret == old))
++		v->counter = new;
++	local_irq_restore(flags);
++
++	return ret;
++}
++
++/**
++ * atomic_add_unless - add unless the number is a given value
++ * @v: pointer of type atomic_t
++ * @a: the amount to add to v...
++ * @u: ...unless v is equal to u.
++ *
++ * Atomically adds @a to @v, so long as it was not @u.
++ * Returns non-zero if @v was not @u, and zero otherwise.
++ */
++static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
++{
++	int c, old;
++	c = atomic_read(v);
++	for (;;) {
++		if (unlikely(c == (u)))
++			break;
++		old = atomic_cmpxchg((v), c, c + (a));
++		if (likely(old == c))
++			break;
++		c = old;
++	}
++	return c != (u);
++}
++#endif
++
+ /*
+  * Generate beacon frame and queue cab data for a VAP.
+  */
+--- /dev/null
++++ b/net80211/sort.c
+@@ -0,0 +1,120 @@
++/*
++ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
++ *
++ * Jan 23 2005  Matt Mackall <mpm@selenic.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++static void u32_swap(void *a, void *b, int size)
++{
++	u32 t = *(u32 *)a;
++	*(u32 *)a = *(u32 *)b;
++	*(u32 *)b = t;
++}
++
++static void generic_swap(void *a, void *b, int size)
++{
++	char t;
++
++	do {
++		t = *(char *)a;
++		*(char *)a++ = *(char *)b;
++		*(char *)b++ = t;
++	} while (--size > 0);
++}
++
++/**
++ * sort - sort an array of elements
++ * @base: pointer to data to sort
++ * @num: number of elements
++ * @size: size of each element
++ * @cmp: pointer to comparison function
++ * @swap: pointer to swap function or NULL
++ *
++ * This function does a heapsort on the given array. You may provide a
++ * swap function optimized to your element type.
++ *
++ * Sorting time is O(n log n) both on average and worst-case. While
++ * qsort is about 20% faster on average, it suffers from exploitable
++ * O(n*n) worst-case behavior and extra memory requirements that make
++ * it less suitable for kernel use.
++ */
++
++static void sort(void *base, size_t num, size_t size,
++	  int (*cmp)(const void *, const void *),
++	  void (*swap)(void *, void *, int size))
++{
++	/* pre-scale counters for performance */
++	int i = (num/2 - 1) * size, n = num * size, c, r;
++
++	if (!swap)
++		swap = (size == 4 ? u32_swap : generic_swap);
++
++	/* heapify */
++	for ( ; i >= 0; i -= size) {
++		for (r = i; r * 2 + size < n; r  = c) {
++			c = r * 2 + size;
++			if (c < n - size && cmp(base + c, base + c + size) < 0)
++				c += size;
++			if (cmp(base + r, base + c) >= 0)
++				break;
++			swap(base + r, base + c, size);
++		}
++	}
++
++	/* sort */
++	for (i = n - size; i >= 0; i -= size) {
++		swap(base, base + i, size);
++		for (r = 0; r * 2 + size < i; r = c) {
++			c = r * 2 + size;
++			if (c < i - size && cmp(base + c, base + c + size) < 0)
++				c += size;
++			if (cmp(base + r, base + c) >= 0)
++				break;
++			swap(base + r, base + c, size);
++		}
++	}
++}
++
++EXPORT_SYMBOL(sort);
++
++#if 0
++/* a simple boot-time regression test */
++
++int cmpint(const void *a, const void *b)
++{
++	return *(int *)a - *(int *)b;
++}
++
++static int sort_test(void)
++{
++	int *a, i, r = 1;
++
++	a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
++	BUG_ON(!a);
++
++	printk("testing sort()\n");
++
++	for (i = 0; i < 1000; i++) {
++		r = (r * 725861) % 6599;
++		a[i] = r;
++	}
++
++	sort(a, 1000, sizeof(int), cmpint, NULL);
++
++	for (i = 0; i < 999; i++)
++		if (a[i] > a[i+1]) {
++			printk("sort() failed!\n");
++			break;
++		}
++
++	kfree(a);
++
++	return 0;
++}
++
++module_init(sort_test);
++#endif
diff --git a/package/madwifi/patches-testing/126-rxerr_frames.patch b/package/madwifi/patches-testing/126-rxerr_frames.patch
new file mode 100644
index 000000000..f95124135
--- /dev/null
+++ b/package/madwifi/patches-testing/126-rxerr_frames.patch
@@ -0,0 +1,27 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6451,9 +6451,6 @@
+ 		rs = &bf->bf_dsstatus.ds_rxstat;
+ 
+ 		len = rs->rs_datalen;
+-		/* DMA sync. dies spectacularly if len == 0 */
+-		if (len == 0)
+-			goto rx_next;
+ 		if (rs->rs_more) {
+ 			/* Frame spans multiple descriptors; this
+ 			 * cannot happen yet as we don't support
+@@ -6513,8 +6510,12 @@
+ 		 * setup again to receive another frame. 
+ 		 * NB: Meta-data (rs, noise, tsf) in the ath_buf is still
+ 		 * used. */
+-		bus_dma_sync_single(sc->sc_bdev,
+-			bf->bf_skbaddr, len, BUS_DMA_FROMDEVICE);
++
++		/* DMA sync. dies spectacularly if len == 0 */
++		if (len != 0) {
++			bus_dma_sync_single(sc->sc_bdev,
++				bf->bf_skbaddr, len, BUS_DMA_FROMDEVICE);
++		}
+ 		skb = ath_rxbuf_take_skb(sc, bf);
+ 
+ 		sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
diff --git a/package/madwifi/patches-testing/200-no_debug.patch b/package/madwifi/patches-testing/200-no_debug.patch
new file mode 100644
index 000000000..0797f8fb6
--- /dev/null
+++ b/package/madwifi/patches-testing/200-no_debug.patch
@@ -0,0 +1,420 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -323,8 +323,10 @@
+ static void ath_set_dfs_cac_time(struct ieee80211com *, unsigned int seconds);
+ 
+ static unsigned int ath_test_radar(struct ieee80211com *);
+-static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
++#ifdef AR_DEBUG
+ 
++static unsigned int ath_dump_hal_map(struct ieee80211com *ic);
++#endif
+ static u_int32_t ath_get_clamped_maxtxpower(struct ath_softc *sc);
+ static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+ 		u_int32_t new_clamped_maxtxpower);
+@@ -334,7 +336,10 @@
+ 		unsigned int param, unsigned int value);
+ 
+ static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
++
++#ifdef AR_DEBUG
+ static int ath_txq_check(struct ath_softc *sc, struct ath_txq *txq, const char *msg);
++#endif
+ 
+ static int ath_countrycode = CTRY_DEFAULT;	/* country code */
+ static int ath_outdoor = AH_FALSE;		/* enable outdoor use */
+@@ -486,9 +491,11 @@
+ 	u_int8_t csz;
+ 
+ 	sc->devid = devid;
++#ifdef AR_DEBUG
+ 	ath_debug_global = (ath_debug & ATH_DEBUG_GLOBAL);
+ 	sc->sc_debug 	 = (ath_debug & ~ATH_DEBUG_GLOBAL);
+ 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
++#endif
+ 
+ 	/* Allocate space for dynamically determined maximum VAP count */
+ 	sc->sc_bslot = 
+@@ -1014,7 +1021,9 @@
+ 	ic->ic_vap_delete = ath_vap_delete;
+ 
+ 	ic->ic_test_radar		= ath_test_radar;
++#ifdef AR_DEBUG
+ 	ic->ic_dump_hal_map		= ath_dump_hal_map;
++#endif
+ 
+ 	ic->ic_set_dfs_testmode		= ath_set_dfs_testmode;
+ 	ic->ic_get_dfs_testmode		= ath_get_dfs_testmode;
+@@ -1285,12 +1294,14 @@
+ 		/* If no default VAP debug flags are passed, allow a few to
+ 		 * transfer down from the driver to new VAPs so we can have load
+ 		 * time debugging for VAPs too. */
++#ifdef AR_DEBUG
+ 		vap->iv_debug = 0 |
+ 			((sc->sc_debug & ATH_DEBUG_RATE) ? IEEE80211_MSG_XRATE  : 0) | 
+ 			((sc->sc_debug & ATH_DEBUG_XMIT) ? IEEE80211_MSG_OUTPUT : 0) | 
+ 			((sc->sc_debug & ATH_DEBUG_RECV) ? IEEE80211_MSG_INPUT  : 0) |
+ 			0
+ 			;
++#endif
+ 	}
+ 	ic->ic_debug = (sc->sc_default_ieee80211_debug & IEEE80211_MSG_IC);
+ 
+@@ -2811,6 +2822,7 @@
+ #endif
+ }
+ 
++#ifdef AR_DEBUG
+ static void
+ ath_txq_dump(struct ath_softc *sc, struct ath_txq *txq)
+ {
+@@ -2866,6 +2878,7 @@
+ 
+ 	return 1;
+ }
++#endif
+ 
+ /*
+  * Insert a buffer on a txq
+@@ -8384,7 +8397,9 @@
+ ath_tx_timeout(struct net_device *dev)
+ {
+ 	struct ath_softc *sc = dev->priv;
++#ifdef AR_DEBUG
+ 	int i;
++#endif
+ 
+ 	if (ath_chan_unavail(sc))
+ 		return;
+@@ -8393,12 +8408,14 @@
+ 		(dev->flags & IFF_RUNNING) ? "" : "NOT ",
+ 		sc->sc_invalid ? "in" : "");
+ 
++#ifdef AR_DEBUG
+ 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+ 		if (ATH_TXQ_SETUP(sc, i)) {
+ 			ath_txq_check(sc, &sc->sc_txq[i], __func__);
+ 			ath_txq_dump(sc, &sc->sc_txq[i]);
+ 		}
+ 	}
++#endif
+ 
+ 	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
+ 		sc->sc_stats.ast_watchdog++;
+@@ -10638,6 +10655,7 @@
+ 				/* XXX validate? */
+ 				sc->sc_ledpin = val;
+ 				break;
++#ifdef AR_DEBUG
+ 			case ATH_DEBUG:
+ 				sc->sc_debug 	 = (val & ~ATH_DEBUG_GLOBAL);
+ 				ath_debug_global = (val &  ATH_DEBUG_GLOBAL);
+@@ -10645,6 +10663,7 @@
+ 						"0x%08x.\n", val);
+ 
+ 				break;
++#endif
+ 			case ATH_TXANTENNA:
+ 				/*
+ 				 * antenna can be:
+@@ -10818,9 +10837,11 @@
+ 		case ATH_REGDOMAIN:
+ 			ath_hal_getregdomain(ah, &val);
+ 			break;
++#ifdef AR_DEBUG
+ 		case ATH_DEBUG:
+ 			val = sc->sc_debug | ath_debug_global;
+ 			break;
++#endif
+ 		case ATH_TXANTENNA:
+ 			val = sc->sc_txantenna;
+ 			break;
+@@ -11939,6 +11960,7 @@
+ }
+ 
+ /* This is called by a private ioctl (iwpriv) to dump the HAL obfuscation table */
++#ifdef AR_DEBUG
+ static unsigned int
+ ath_dump_hal_map(struct ieee80211com *ic)
+ {
+@@ -11947,7 +11969,7 @@
+ 	ath_hal_dump_map(sc->sc_ah);
+ 	return 0;
+ }
+-
++#endif
+ /* If we are shutting down or blowing off the DFS channel availability check
+  * then we call this to stop the behavior before we take the rest of the
+  * necessary actions (such as a DFS reaction to radar). */
+--- a/ath_rate/amrr/amrr.c
++++ b/ath_rate/amrr/amrr.c
+@@ -70,7 +70,9 @@
+ 
+ #include "amrr.h"
+ 
++#ifdef AR_DEBUG
+ #define	AMRR_DEBUG
++#endif
+ #ifdef AMRR_DEBUG
+ #define	DPRINTF(sc, _fmt, ...) do {					\
+ 	if (sc->sc_debug & 0x10)					\
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -117,7 +117,9 @@
+ 
+ #include "minstrel.h"
+ 
++#ifdef AR_DEBUG
+ #define	MINSTREL_DEBUG
++#endif
+ #ifdef MINSTREL_DEBUG
+ enum {
+ 		ATH_DEBUG_RATE		= 0x00000010	/* rate control */
+@@ -963,7 +965,9 @@
+ 		(struct ieee80211_node_table *)&vap->iv_ic->ic_sta;
+ 	unsigned int x = 0;
+ 	unsigned int this_tp, this_prob, this_eprob;
+-	struct ath_softc *sc = vap->iv_ic->ic_dev->priv;;
++#ifdef AR_DEBUG
++	struct ath_softc *sc = vap->iv_ic->ic_dev->priv;
++#endif
+ 
+ 	IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+ 	TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
+--- a/ath_rate/onoe/onoe.c
++++ b/ath_rate/onoe/onoe.c
+@@ -66,7 +66,9 @@
+ 
+ #include "onoe.h"
+ 
++#ifdef AR_DEBUG
+ #define	ONOE_DEBUG
++#endif
+ #ifdef ONOE_DEBUG
+ enum {
+ 	ATH_DEBUG_RATE	= 0x00000010,	/* rate control */
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -68,7 +68,9 @@
+ 
+ #include "sample.h"
+ 
+-#define	SAMPLE_DEBUG
++#ifdef AR_DEBUG
++#define SAMPLE_DEBUG
++#endif
+ #ifdef SAMPLE_DEBUG
+ enum {
+ 	ATH_DEBUG_RATE		= 0x00000010,	/* rate control */
+--- a/tools/do_multi.c
++++ b/tools/do_multi.c
+@@ -9,16 +9,20 @@
+ 
+     progname = basename(argv[0]);
+ 
++#ifdef AR_DEBUG
+     if(strcmp(progname, "80211debug") == 0)
+ 	ret = a80211debug_init(argc, argv);
++#endif
+     if(strcmp(progname, "80211stats") == 0)
+ 	ret = a80211stats_init(argc, argv);
+     if(strcmp(progname, "athchans") == 0)
+ 	ret = athchans_init(argc, argv);
+     if(strcmp(progname, "athctrl") == 0)
+ 	ret =  athctrl_init(argc, argv);
++#ifdef AR_DEBUG
+     if(strcmp(progname, "athdebug") == 0)
+ 	ret =  athdebug_init(argc, argv);
++#endif
+     if(strcmp(progname, "athkey") == 0)
+ 	ret =  athkey_init(argc, argv);
+     if(strcmp(progname, "athstats") == 0)
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -39,6 +39,10 @@
+ 
+ ATH_HAL = $(TOP)/ath_hal
+ 
++ifndef ATH_DEBUG
++ATH_DEBUG=1
++endif
++
+ #
+ # Path to the HAL source code.
+ #
+@@ -46,17 +50,22 @@
+ HAL = $(TOP)/hal
+ endif
+ 
++INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
++CFLAGS = -g -O2 -Wall
++ALL_CFLAGS = $(CFLAGS) $(INCS)
++LDFLAGS =
+ 
+ PROGRAMS = athstats 80211stats athkey athchans athctrl \
+-	athdebug 80211debug wlanconfig wpakey
++	wlanconfig wpakey
++
++ifeq ($(ATH_DEBUG),1)
++  PROGRAMS += athdebug 80211debug
++  ALL_CFLAGS += -DAR_DEBUG
++endif
+ 
+ OBJS = $(patsubst %,%.o,$(PROGRAMS)) ath_info/ath_info.o
+ SUBDIRS = ath_info
+ 
+-INCS = -I. -I$(HAL) -I$(TOP) -I$(ATH_HAL) -I$(TOP)/ath
+-CFLAGS = -g -O2 -Wall
+-ALL_CFLAGS = $(CFLAGS) $(INCS)
+-LDFLAGS =
+ 
+ all: all-subdirs compile
+ 
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -1263,6 +1263,7 @@
+ 
+            tail -f /var/log/messages | sed -f hal_unmangle.sed 
+  */
++#ifdef AR_DEBUG
+ static inline void ath_hal_dump_map(struct ath_hal *ah)
+ {
+ #ifdef CONFIG_KALLSYMS
+@@ -1527,7 +1528,7 @@
+ #endif				/* #ifndef CONFIG_KALLSYMS */
+ 
+ }
+-
++#endif
+ #include "if_ath_hal_wrappers.h"
+ #include "if_ath_hal_extensions.h"
+ 
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -495,9 +495,10 @@
+ 	/* inject a fake radar signal -- used while on a 802.11h DFS channels */
+ 	unsigned int (*ic_test_radar)(struct ieee80211com *);
+ 
++#ifdef AR_DEBUG
+ 	/* dump HAL */
+ 	unsigned int (*ic_dump_hal_map)(struct ieee80211com *);
+-
++#endif
+ 	/* DFS channel availability check time (in seconds) */
+ 	void (*ic_set_dfs_cac_time)(struct ieee80211com *, unsigned int);
+ 	unsigned int (*ic_get_dfs_cac_time)(struct ieee80211com *);
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -1557,6 +1557,7 @@
+ 	return 0;
+ }
+ 
++#ifdef AR_DEBUG
+ static int 
+ ieee80211_ioctl_hal_map(struct net_device *dev, struct iw_request_info *info,
+        void *w, char *extra)
+@@ -1567,7 +1568,7 @@
+        params[0] = ic->ic_dump_hal_map(ic);
+        return 0;
+ }
+-
++#endif
+ 
+ static int
+ ieee80211_ioctl_radar(struct net_device *dev, struct iw_request_info *info,
+@@ -5296,8 +5297,10 @@
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,   "getwmmparams" },
+ 	{ IEEE80211_IOCTL_RADAR,
+ 	  0, 0, "doth_radar" },
++#ifdef AR_DEBUG
+ 	{ IEEE80211_IOCTL_HALMAP,
+ 	  0, 0, "dump_hal_map" },
++#endif
+ 	/*
+ 	 * These depends on sub-ioctl support which added in version 12.
+ 	 */
+@@ -5751,7 +5754,9 @@
+ 	set_priv(IEEE80211_IOCTL_SETMLME, ieee80211_ioctl_setmlme),
+ 	set_priv(IEEE80211_IOCTL_SETKEY, ieee80211_ioctl_setkey),
+ 	set_priv(IEEE80211_IOCTL_DELKEY, ieee80211_ioctl_delkey),
++#ifdef AR_DEBUG
+ 	set_priv(IEEE80211_IOCTL_HALMAP, ieee80211_ioctl_hal_map),
++#endif
+ 	set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac),
+ 	set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac),
+ 	set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
+--- a/ath/if_ath_debug.h
++++ b/ath/if_ath_debug.h
+@@ -54,6 +54,10 @@
+ 	ATH_DEBUG_GLOBAL	= (ATH_DEBUG_SKB|ATH_DEBUG_SKB_REF)
+ };
+ 
++#define	EPRINTF(_sc, _fmt, ...) \
++		printk(KERN_ERR "%s: %s: " _fmt, \
++			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
++
+ #ifdef AR_DEBUG
+ 
+ /* DEBUG-ONLY DEFINITIONS */
+@@ -68,20 +72,9 @@
+ 		ath_keyprint((_sc), __func__, _ix, _hk, _mac);		\
+ } while (0)
+ 
+-#else /* #ifdef AR_DEBUG */
+-
+-#define	DFLAG_ISSET(sc, _m)		0
+-#define	DPRINTF(sc, _m, _fmt, ...)
+-#define	KEYPRINTF(sc, k, ix, mac)
+-
+-#endif /* #ifdef AR_DEBUG */
+ 
+ #define	IFF_DUMPPKTS(_sc, _m)   DFLAG_ISSET((_sc), (_m))
+ 
+-#define	EPRINTF(_sc, _fmt, ...) \
+-		printk(KERN_ERR "%s: %s: " _fmt, \
+-			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
+-
+ #define	WPRINTF(_sc, _fmt, ...) \
+ 		printk(KERN_WARNING "%s: %s: " _fmt, \
+ 			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
+@@ -89,5 +82,14 @@
+ #define	IPRINTF(_sc, _fmt, ...) \
+ 		printk(KERN_INFO "%s: %s: " _fmt, \
+ 			SC_DEV_NAME(_sc), __func__, ## __VA_ARGS__)
++#else
++#define	DFLAG_ISSET(sc, _m)		0
++#define	DPRINTF(sc, _m, _fmt, ...)
++#define	KEYPRINTF(sc, k, ix, mac)
++#define WPRINTF(...)
++#define IPRINTF(...)
++#define IFF_DUMPPKTS(...) 0
++
++#endif
+ 
+ #endif /* #ifndef _IF_ATH_DEBUG_H_ */
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -134,8 +134,10 @@
+ 	u16 vdevice;
+ 	int i;
+ 
+-	if (pci_enable_device(pdev))
++	if (pci_enable_device(pdev)) {
++		printk(KERN_ERR "%s: failed to enable PCI device\n", dev_info);
+ 		return -EIO;
++	}
+ 
+ 	/* XXX 32-bit addressing only */
+ 	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+@@ -244,8 +246,10 @@
+ 		sc->aps_sc.sc_ledpin = 1;
+ 	}
+ 
+-	if (ath_attach(vdevice, dev, NULL) != 0)
++	if ((i = ath_attach(vdevice, dev, NULL)) != 0) {
++		printk(KERN_ERR "%s: ath_attach failed: %d\n", dev_info, i);
+ 		goto bad4;
++	}
+ 
+ 	athname = ath_hal_probe(id->vendor, vdevice);
+ 	printk(KERN_INFO "%s: %s: %s: mem=0x%llx, irq=%d\n",
diff --git a/package/madwifi/patches-testing/201-no_debug_extra.patch b/package/madwifi/patches-testing/201-no_debug_extra.patch
new file mode 100644
index 000000000..0e26d5f39
--- /dev/null
+++ b/package/madwifi/patches-testing/201-no_debug_extra.patch
@@ -0,0 +1,33 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -423,8 +423,8 @@
+ 		"defaults to '" DEF_RATE_CTL "'");
+ MODULE_PARM_DESC(intmit, "Enable interference mitigation by default.  Default is 0.");
+ 
+-static int	ath_debug = 0;
+ #ifdef AR_DEBUG
++static int	ath_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ath_debug, "i");
+ #else
+@@ -435,8 +435,8 @@
+ static void ath_printtxbuf(const struct ath_buf *, int);
+ #endif /* defined(AR_DEBUG) */
+ 
+-static int	ieee80211_debug = 0;
+ #ifdef AR_DEBUG
++static int	ieee80211_debug = 0;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
+ MODULE_PARM(ieee80211_debug, "i");
+ #else
+@@ -853,8 +853,10 @@
+ 	ic->ic_updateslot = ath_updateslot;
+ 	atomic_set(&ic->ic_node_counter, 0);
+ 	ic->ic_debug = 0;
++#ifdef AR_DEBUG
+ 	sc->sc_debug = (ath_debug & ~ATH_DEBUG_GLOBAL);
+ 	sc->sc_default_ieee80211_debug = ieee80211_debug;
++#endif
+ 
+ 	ic->ic_wme.wme_update = ath_wme_update;
+ 	ic->ic_uapsd_flush = ath_uapsd_flush;
diff --git a/package/madwifi/patches-testing/300-napi_polling.patch b/package/madwifi/patches-testing/300-napi_polling.patch
new file mode 100644
index 000000000..27dd838db
--- /dev/null
+++ b/package/madwifi/patches-testing/300-napi_polling.patch
@@ -0,0 +1,529 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -182,7 +182,11 @@
+ 	struct sk_buff *, int, int, u_int64_t);
+ static void ath_setdefantenna(struct ath_softc *, u_int);
+ static struct ath_txq *ath_txq_setup(struct ath_softc *, int, int);
+-static void ath_rx_tasklet(TQUEUE_ARG);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++static int ath_rx_poll(struct napi_struct *napi, int budget);
++#else
++static int ath_rx_poll(struct net_device *dev, int *budget);
++#endif
+ static int ath_hardstart(struct sk_buff *, struct net_device *);
+ static int ath_mgtstart(struct ieee80211com *, struct sk_buff *);
+ #ifdef ATH_SUPERG_COMP
+@@ -331,6 +335,9 @@
+ static u_int32_t ath_set_clamped_maxtxpower(struct ath_softc *sc, 
+ 		u_int32_t new_clamped_maxtxpower);
+ 
++static void ath_poll_disable(struct net_device *dev);
++static void ath_poll_enable(struct net_device *dev);
++
+ static void ath_scanbufs(struct ath_softc *sc);
+ static int ath_debug_iwpriv(struct ieee80211com *ic, 
+ 		unsigned int param, unsigned int value);
+@@ -518,7 +525,6 @@
+ 
+ 	atomic_set(&sc->sc_txbuf_counter, 0);
+ 
+-	ATH_INIT_TQUEUE(&sc->sc_rxtq,		ath_rx_tasklet,		dev);
+ 	ATH_INIT_TQUEUE(&sc->sc_txtq,		ath_tx_tasklet,		dev);
+ 	ATH_INIT_TQUEUE(&sc->sc_bmisstq,	ath_bmiss_tasklet,	dev);
+ 	ATH_INIT_TQUEUE(&sc->sc_bstucktq,	ath_bstuck_tasklet,	dev);
+@@ -833,6 +839,12 @@
+ 	dev->set_mac_address = ath_set_mac_address;
+ 	dev->change_mtu = ath_change_mtu;
+ 	dev->tx_queue_len = ATH_TXBUF - ATH_TXBUF_MGT_RESERVED;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	netif_napi_add(dev, &sc->sc_napi, ath_rx_poll, 64);
++#else
++	dev->poll = ath_rx_poll;
++	dev->weight = 64;
++#endif
+ #ifdef USE_HEADERLEN_RESV
+ 	dev->hard_header_len += sizeof(struct ieee80211_qosframe) +
+ 				sizeof(struct llc) +
+@@ -1770,7 +1782,7 @@
+ }
+ 
+ static void
+-ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf)
++ath_intr_process_rx_descriptors(struct ath_softc *sc, int *pneedmark, u_int64_t hw_tsf, int schedule)
+ {
+ 	struct ath_hal *ah = sc->sc_ah;
+ 	struct ath_desc *ds;
+@@ -2252,8 +2264,25 @@
+ 	}
+ 
+ 	/* If we got something to process, schedule rx queue to handle it */
+-	if (count)
+-		ATH_SCHEDULE_TQUEUE(&sc->sc_rxtq, pneedmark);
++	if (count) {
++		sc->sc_isr &= ~HAL_INT_RX;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++		if (netif_rx_schedule_prep(sc->sc_dev, &sc->sc_napi))
++#else
++		if (netif_rx_schedule_prep(sc->sc_dev))
++#endif
++		{
++#ifndef ATH_PRECISE_TSF
++			sc->sc_imask &= ~HAL_INT_RX;
++			ath_hal_intrset(ah, sc->sc_imask);
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++			__netif_rx_schedule(sc->sc_dev, &sc->sc_napi);
++#else
++			__netif_rx_schedule(sc->sc_dev);
++#endif
++		}
++	}
+ 	ATH_RXBUF_UNLOCK_IRQ(sc);
+ #undef PA2DESC
+ }
+@@ -2343,6 +2372,7 @@
+ 		(status & HAL_INT_GLOBAL)	? " HAL_INT_GLOBAL"	: ""
+ 		);
+ 
++	sc->sc_isr = status;
+ 	status &= sc->sc_imask;			/* discard unasked for bits */
+ 	/* As soon as we know we have a real interrupt we intend to service, 
+ 	 * we will check to see if we need an initial hardware TSF reading. 
+@@ -2400,7 +2430,7 @@
+ 		}
+ 		if (status & (HAL_INT_RX | HAL_INT_RXPHY)) {
+ 			/* NB: Will schedule rx tasklet if necessary. */
+-			ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf);
++			ath_intr_process_rx_descriptors(sc, &needmark, hw_tsf, 1);
+ 		}
+ 		if (status & HAL_INT_TX) {
+ #ifdef ATH_SUPERG_DYNTURBO
+@@ -2426,6 +2456,11 @@
+ 				}
+ 			}
+ #endif
++			/* disable transmit interrupt */
++			sc->sc_isr &= ~HAL_INT_TX;
++			ath_hal_intrset(ah, sc->sc_imask & ~HAL_INT_TX);
++			sc->sc_imask &= ~HAL_INT_TX;
++
+ 			ATH_SCHEDULE_TQUEUE(&sc->sc_txtq, &needmark);
+ 		}
+ 		if (status & HAL_INT_BMISS) {
+@@ -2617,6 +2652,7 @@
+ 	if (sc->sc_tx99 != NULL)
+ 		sc->sc_tx99->start(sc->sc_tx99);
+ #endif
++	ath_poll_enable(dev);
+ 
+ done:
+ 	ATH_UNLOCK(sc);
+@@ -2657,6 +2693,9 @@
+ 		if (sc->sc_tx99 != NULL)
+ 			sc->sc_tx99->stop(sc->sc_tx99);
+ #endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++		ath_poll_disable(dev);
++#endif
+ 		netif_stop_queue(dev);	/* XXX re-enabled by ath_newstate */
+ 		dev->flags &= ~IFF_RUNNING;	/* NB: avoid recursion */
+ 		ieee80211_stop_running(ic);	/* stop all VAPs */
+@@ -4109,6 +4148,43 @@
+ 	return ath_keyset(sc, k, mac, vap->iv_bss);
+ }
+ 
++static void ath_poll_disable(struct net_device *dev)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	struct ath_softc *sc = dev->priv;
++#endif
++
++	/*
++	 * XXX Using in_softirq is not right since we might
++	 * be called from other soft irq contexts than
++	 * ath_rx_poll
++	 */
++	if (!in_softirq()) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++		napi_disable(&sc->sc_napi);
++#else
++		netif_poll_disable(dev);
++#endif
++	}
++}
++
++static void ath_poll_enable(struct net_device *dev)
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	struct ath_softc *sc = dev->priv;
++#endif
++
++	/* NB: see above */
++	if (!in_softirq()) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++		napi_enable(&sc->sc_napi);
++#else
++		netif_poll_enable(dev);
++#endif
++	}
++}
++
++
+ /*
+  * Block/unblock tx+rx processing while a key change is done.
+  * We assume the caller serializes key management operations
+@@ -4119,33 +4195,23 @@
+ ath_key_update_begin(struct ieee80211vap *vap)
+ {
+ 	struct net_device *dev = vap->iv_ic->ic_dev;
+-	struct ath_softc *sc = dev->priv;
+ 
+-	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "Begin\n");
+ 	/*
+ 	 * When called from the rx tasklet we cannot use
+ 	 * tasklet_disable because it will block waiting
+ 	 * for us to complete execution.
+-	 *
+-	 * XXX Using in_softirq is not right since we might
+-	 * be called from other soft irq contexts than
+-	 * ath_rx_tasklet.
+ 	 */
+-	if (!in_softirq())
+-		tasklet_disable(&sc->sc_rxtq);
+-	netif_stop_queue(dev);
++	if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
++		netif_stop_queue(dev);
+ }
+ 
+ static void
+ ath_key_update_end(struct ieee80211vap *vap)
+ {
+ 	struct net_device *dev = vap->iv_ic->ic_dev;
+-	struct ath_softc *sc = dev->priv;
+ 
+-	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "End\n");
+-	netif_wake_queue(dev);
+-	if (!in_softirq())		/* NB: see above */
+-		tasklet_enable(&sc->sc_rxtq);
++	if ((dev->flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))
++		netif_wake_queue(dev);
+ }
+ 
+ /*
+@@ -6405,15 +6471,25 @@
+ 	sc->sc_numrxotherant = 0;
+ }
+ 
+-static void
+-ath_rx_tasklet(TQUEUE_ARG data)
++static int
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++ath_rx_poll(struct napi_struct *napi, int budget)
++#else
++ath_rx_poll(struct net_device *dev, int *budget)
++#endif
+ {
+ #define	PA2DESC(_sc, _pa) \
+ 	((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ 		((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+-	struct net_device *dev = (struct net_device *)data;
+-	struct ath_buf *bf;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	struct ath_softc *sc = container_of(napi, struct ath_softc, sc_napi);
++	struct net_device *dev = sc->sc_dev;
++	u_int rx_limit = budget;
++#else
+ 	struct ath_softc *sc = dev->priv;
++	u_int rx_limit = min(dev->quota, *budget);
++#endif
++	struct ath_buf *bf;
+ 	struct ieee80211com *ic = &sc->sc_ic;
+ 	struct ath_hal *ah = sc ? sc->sc_ah : NULL;
+ 	struct ath_desc *ds;
+@@ -6421,6 +6497,7 @@
+ 	struct ieee80211_node *ni;
+ 	struct sk_buff *skb = NULL;
+ 	unsigned int len, phyerr, mic_fail = 0;
++	unsigned int early_stop = 0;
+ 	int type = -1; /* undefined */
+ 	int init_ret = 0;
+ 	int bf_processed = 0;
+@@ -6428,6 +6505,7 @@
+ 	int errors	 = 0;
+ 
+ 	DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s started...\n", __func__);
++process_rx_again:
+ 	do {
+ 		/* Get next RX buffer pending processing by RX tasklet...
+ 		 *  
+@@ -6457,6 +6535,10 @@
+ 			break;
+ 
+ 		bf_processed++;
++		if (rx_limit-- < 0) {
++			early_stop = 1;
++			break;
++		}
+ 		ds  = bf->bf_desc;
+ 
+ #ifdef AR_DEBUG
+@@ -6491,6 +6573,7 @@
+ 				sc->sc_stats.ast_rx_phyerr++;
+ 				phyerr = rs->rs_phyerr & 0x1f;
+ 				sc->sc_stats.ast_rx_phy[phyerr]++;
++				goto rx_next;
+ 			}
+ 			if (rs->rs_status & HAL_RXERR_DECRYPT) {
+ 				/* Decrypt error.  If the error occurred
+@@ -6689,6 +6772,33 @@
+ 		STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
+ 		ATH_RXBUF_UNLOCK_IRQ(sc);
+ 	} while (1);
++	if (!early_stop) {
++		unsigned long flags;
++		/* Check if more data is received while we were
++		 * processing the descriptor chain.
++		 */
++#ifndef ATH_PRECISE_TSF
++		local_irq_save(flags);
++		if (sc->sc_isr & HAL_INT_RX) {
++			u_int64_t hw_tsf = ath_hal_gettsf64(ah);
++			sc->sc_isr &= ~HAL_INT_RX;
++			local_irq_restore(flags);
++			ath_intr_process_rx_descriptors(sc, NULL, hw_tsf, 0);
++			goto process_rx_again;
++		}
++		sc->sc_imask |= HAL_INT_RX;
++		ath_hal_intrset(ah, sc->sc_imask);
++		local_irq_restore(flags);
++#endif
++	}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	netif_rx_complete(dev, napi);
++#else
++	netif_rx_complete(dev);
++	*budget -= bf_processed;
++	dev->quota -= bf_processed;
++#endif
+ 
+ 	if (sc->sc_useintmit) 
+ 		ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
+@@ -6701,6 +6811,12 @@
+ 		" %d rx buf processed. %d were errors. %d skb accepted.\n",
+ 		__func__, bf_processed, errors, skb_accepted);
+ #undef PA2DESC
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	return bf_processed;
++#else
++	return early_stop;
++#endif
+ }
+ 
+ #ifdef ATH_SUPERG_XR
+@@ -8306,12 +8422,24 @@
+ {
+ 	struct net_device *dev = (struct net_device *)data;
+ 	struct ath_softc *sc = dev->priv;
++	unsigned long flags;
+ 
++process_tx_again:
+ 	if (txqactive(sc->sc_ah, 0))
+ 		ath_tx_processq(sc, &sc->sc_txq[0]);
+ 	if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
+ 		ath_tx_processq(sc, sc->sc_cabq);
+ 
++	local_irq_save(flags);
++	if (sc->sc_isr & HAL_INT_TX) {
++		sc->sc_isr &= ~HAL_INT_TX;
++		local_irq_restore(flags);
++		goto process_tx_again;
++	}
++	sc->sc_imask |= HAL_INT_TX;
++	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++	local_irq_restore(flags);
++
+ 	netif_wake_queue(dev);
+ 
+ 	if (sc->sc_softled)
+@@ -8327,7 +8455,9 @@
+ {
+ 	struct net_device *dev = (struct net_device *)data;
+ 	struct ath_softc *sc = dev->priv;
++	unsigned long flags;
+ 
++process_tx_again:
+ 	/*
+ 	 * Process each active queue.
+ 	 */
+@@ -8357,6 +8487,16 @@
+ 	if (sc->sc_uapsdq && txqactive(sc->sc_ah, sc->sc_uapsdq->axq_qnum))
+ 		ath_tx_processq(sc, sc->sc_uapsdq);
+ 
++	local_irq_save(flags);
++	if (sc->sc_isr & HAL_INT_TX) {
++		sc->sc_isr &= ~HAL_INT_TX;
++		local_irq_restore(flags);
++		goto process_tx_again;
++	}
++	sc->sc_imask |= HAL_INT_TX;
++	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++	local_irq_restore(flags);
++
+ 	netif_wake_queue(dev);
+ 
+ 	if (sc->sc_softled)
+@@ -10322,9 +10462,9 @@
+ 	dev->mtu = mtu;
+ 	if ((dev->flags & IFF_RUNNING) && !sc->sc_invalid) {
+ 		/* NB: the rx buffers may need to be reallocated */
+-		tasklet_disable(&sc->sc_rxtq);
++		ath_poll_disable(dev);
+ 		error = ath_reset(dev);
+-		tasklet_enable(&sc->sc_rxtq);
++		ath_poll_enable(dev);
+ 	}
+ 	ATH_UNLOCK(sc);
+ 
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -56,6 +56,10 @@
+ # include	<asm/bitops.h>
+ #endif
+ 
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++#define irqs_disabled()			0
++#endif
++
+ /*
+  * Deduce if tasklets are available.  If not then
+  * fall back to using the immediate work queue.
+@@ -644,6 +648,9 @@
+ struct ath_softc {
+ 	struct ieee80211com sc_ic;		/* NB: must be first */
+ 	struct net_device *sc_dev;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++	struct napi_struct sc_napi;
++#endif
+ 	void __iomem *sc_iobase;		/* address of the device */
+ 	struct semaphore sc_lock;		/* dev-level lock */
+ 	struct net_device_stats	sc_devstats;	/* device statistics */
+@@ -756,7 +763,6 @@
+ 	struct ath_buf *sc_rxbufcur;		/* current rx buffer */
+ 	u_int32_t *sc_rxlink;			/* link ptr in last RX desc */
+ 	spinlock_t sc_rxbuflock;
+-	struct ATH_TQ_STRUCT sc_rxtq;		/* rx intr tasklet */
+ 	struct ATH_TQ_STRUCT sc_rxorntq;	/* rxorn intr tasklet */
+ 	u_int16_t sc_cachelsz;			/* cache line size */
+ 
+@@ -769,6 +775,7 @@
+ 	u_int sc_txintrperiod;			/* tx interrupt batching */
+ 	struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
+ 	struct ath_txq *sc_ac2q[WME_NUM_AC];	/* WME AC -> h/w qnum */
++	HAL_INT sc_isr;				/* unmasked ISR state */
+ 	struct ATH_TQ_STRUCT sc_txtq;		/* tx intr tasklet */
+ 	u_int8_t sc_grppoll_str[GRPPOLL_RATE_STR_LEN];
+ 	struct ath_descdma sc_bdma;		/* beacon descriptors */
+@@ -888,6 +895,8 @@
+ #define	ATH_TXBUF_LOCK_CHECK(_sc)
+ #endif
+ 
++#define ATH_DISABLE_INTR		local_irq_disable
++#define ATH_ENABLE_INTR 		local_irq_enable
+ 
+ #define	ATH_RXBUF_LOCK_INIT(_sc)	spin_lock_init(&(_sc)->sc_rxbuflock)
+ #define	ATH_RXBUF_LOCK_DESTROY(_sc)
+--- a/net80211/ieee80211_skb.c
++++ b/net80211/ieee80211_skb.c
+@@ -73,7 +73,7 @@
+ #undef dev_queue_xmit
+ #undef kfree_skb
+ #undef kfree_skb_fast
+-#undef netif_rx
++#undef netif_receive_skb
+ #undef pskb_copy
+ #undef skb_clone
+ #undef skb_copy
+@@ -581,8 +581,8 @@
+ 		grp, vlan_tag);
+ }
+ 
+-int netif_rx_debug(struct sk_buff *skb, const char *func, int line) {
+-	return netif_rx(untrack_skb(skb, 0, __func__, __LINE__));
++int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line) {
++	return netif_receive_skb(untrack_skb(skb, 0, __func__, __LINE__));
+ }
+ 
+ struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
+@@ -707,7 +707,7 @@
+ }
+ 
+ EXPORT_SYMBOL(vlan_hwaccel_rx_debug);
+-EXPORT_SYMBOL(netif_rx_debug);
++EXPORT_SYMBOL(netif_receive_skb_debug);
+ EXPORT_SYMBOL(alloc_skb_debug);
+ EXPORT_SYMBOL(dev_alloc_skb_debug);
+ EXPORT_SYMBOL(skb_clone_debug);
+--- a/net80211/ieee80211_skb.h
++++ b/net80211/ieee80211_skb.h
+@@ -115,7 +115,7 @@
+ 
+ int vlan_hwaccel_rx_debug(struct sk_buff *skb, struct vlan_group *grp,
+ 		unsigned short vlan_tag, const char *func, int line);
+-int netif_rx_debug(struct sk_buff *skb, const char *func, int line);
++int netif_receive_skb_debug(struct sk_buff *skb, const char *func, int line);
+ struct sk_buff *alloc_skb_debug(unsigned int length, gfp_t gfp_mask,
+ 		const char *func, int line);
+ struct sk_buff *dev_alloc_skb_debug(unsigned int length,
+@@ -150,7 +150,7 @@
+ #undef dev_queue_xmit
+ #undef kfree_skb
+ #undef kfree_skb_fast
+-#undef netif_rx
++#undef netif_receive_skb
+ #undef pskb_copy
+ #undef skb_clone
+ #undef skb_copy
+@@ -167,8 +167,8 @@
+ 	skb_copy_expand_debug(_skb, _newheadroom, _newtailroom, _gfp_mask, __func__, __LINE__)
+ #define vlan_hwaccel_rx(_skb, _grp, _tag) \
+ 	vlan_hwaccel_rx_debug(_skb, _grp, _tag, __func__, __LINE__)
+-#define netif_rx(_skb) \
+-	netif_rx_debug(_skb, __func__, __LINE__)
++#define netif_receive_skb(_skb) \
++	netif_receive_skb_debug(_skb, __func__, __LINE__)
+ #define	alloc_skb(_length, _gfp_mask) \
+ 	alloc_skb_debug(_length, _gfp_mask, __func__, __LINE__)
+ #define	dev_alloc_skb(_length) \
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1185,7 +1185,7 @@
+ 			ret = vlan_hwaccel_rx(skb,
+ 					vap->iv_vlgrp, ni->ni_vlan);
+ 		else
+-			ret = netif_rx(skb);
++			ret = netif_receive_skb(skb);
+ 		if (ret == NET_RX_DROP)
+ 			vap->iv_devstats.rx_dropped++;
+ 		if (tni != NULL)
+@@ -2285,7 +2285,7 @@
+ 
+ 		if (SKB_NI(skb1) != NULL)
+ 			ieee80211_unref_node(&SKB_NI(skb1));
+-		if (netif_rx(skb1) == NET_RX_DROP)
++		if (netif_receive_skb(skb1) == NET_RX_DROP)
+ 			vap->iv_devstats.rx_dropped++;
+ 	}
+ }
+--- a/net80211/ieee80211_monitor.c
++++ b/net80211/ieee80211_monitor.c
+@@ -580,7 +580,7 @@
+ 
+ 			if (SKB_NI(skb1) != NULL)
+ 				ieee80211_unref_node(&SKB_NI(skb1));
+-			if (netif_rx(skb1) == NET_RX_DROP)
++			if (netif_receive_skb(skb1) == NET_RX_DROP)
+ 				vap->iv_devstats.rx_dropped++;
+ 			skb1 = NULL;
+ 		}
diff --git a/package/madwifi/patches-testing/301-pureg_fix.patch b/package/madwifi/patches-testing/301-pureg_fix.patch
new file mode 100644
index 000000000..fb6cefe36
--- /dev/null
+++ b/package/madwifi/patches-testing/301-pureg_fix.patch
@@ -0,0 +1,168 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -4251,7 +4251,9 @@
+ 		rfilt |= HAL_RX_FILTER_PROM;
+ 	if (ic->ic_opmode == IEEE80211_M_STA ||
+ 	    sc->sc_opmode == HAL_M_IBSS ||	/* NB: AHDEMO too */
+-	    (sc->sc_nostabeacons) || sc->sc_scanning)
++	    (sc->sc_nostabeacons) || sc->sc_scanning ||
++		((ic->ic_opmode == IEEE80211_M_HOSTAP) &&
++		 (ic->ic_protmode != IEEE80211_PROT_NONE)))
+ 		rfilt |= HAL_RX_FILTER_BEACON;
+ 	if (sc->sc_nmonvaps > 0)
+ 		rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -325,11 +325,12 @@
+ 				bssid = wh->i_addr3;
+ 			}
+ 			/*
+-			 * Validate the bssid.
++			 * Validate the bssid. Let beacons get through though for 11g protection mode.
+ 			 */
+-#ifdef ATH_SUPERG_XR
+ 			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
+-			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
++			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast) &&
++				(subtype != IEEE80211_FC0_SUBTYPE_BEACON)) {
++#ifdef ATH_SUPERG_XR
+ 				/*
+ 				 * allow MGT frames to vap->iv_xrvap.
+ 				 * this will allow roaming between  XR and normal vaps
+@@ -345,18 +346,14 @@
+ 					vap->iv_stats.is_rx_wrongbss++;
+ 					goto out;
+ 				}
+-			}
+ #else
+-			if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bssid) &&
+-			    !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) {
+ 				/* not interested in */
+ 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+ 					bssid, NULL, "%s", "not to bss");
+ 				vap->iv_stats.is_rx_wrongbss++;
+ 				goto out;
+-			}
+-
+ #endif
++			}
+ 			break;
+ 		case IEEE80211_M_WDS:
+ 			if (skb->len < sizeof(struct ieee80211_frame_addr4)) {
+@@ -3019,7 +3016,7 @@
+ 	u_int8_t *frm, *efrm;
+ 	u_int8_t *ssid, *rates, *xrates, *suppchan, *wpa, *rsn, *wme, *ath;
+ 	u_int8_t rate;
+-	int reassoc, resp, allocbs = 0;
++	int reassoc, resp, allocbs = 0, has_erp = 0;
+ 	u_int8_t qosinfo;
+ 
+ 	if (ni_or_null == NULL)
+@@ -3049,11 +3046,15 @@
+ 		 *    o station mode when associated (to collect state
+ 		 *      updates such as 802.11g slot time), or
+ 		 *    o adhoc mode (to discover neighbors)
++		 *    o ap mode in protection mode (beacons only)
+ 		 * Frames otherwise received are discarded.
+ 		 */
+ 		if (!((ic->ic_flags & IEEE80211_F_SCAN) ||
+ 		    (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
+-		    vap->iv_opmode == IEEE80211_M_IBSS)) {
++		    (vap->iv_opmode == IEEE80211_M_IBSS) ||
++			((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
++			 (vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++			 (ic->ic_protmode != IEEE80211_PROT_NONE)))) {
+ 			vap->iv_stats.is_rx_mgtdiscard++;
+ 			return 0;
+ 		}
+@@ -3137,6 +3138,7 @@
+ 					break;
+ 				}
+ 				scan.erp = frm[2];
++				has_erp = 1;
+ 				break;
+ 			case IEEE80211_ELEMID_RSN:
+ 				scan.rsn = frm;
+@@ -3374,6 +3376,20 @@
+ 				ieee80211_bg_scan(vap);
+ 			return 0;
+ 		}
++
++		/* Update AP protection mode when in 11G mode */
++		if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++			IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
++
++			/* Assume no ERP IE == 11b AP */
++			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
++				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
++
++				ic->ic_flags |= IEEE80211_F_USEPROT;
++				ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++			}
++		}
++
+ 		/*
+ 		 * If scanning, just pass information to the scan module.
+ 		 */
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -345,10 +345,16 @@
+ 	/* Update country ie information */
+ 	ieee80211_build_countryie(ic);
+ 
+-	if (IEEE80211_IS_CHAN_HALF(chan))
++	if (IEEE80211_IS_CHAN_HALF(chan)) {
+ 		ni->ni_rates = ic->ic_sup_half_rates;
+-	else if (IEEE80211_IS_CHAN_QUARTER(chan))
++	} else if (IEEE80211_IS_CHAN_QUARTER(chan)) {
+ 		ni->ni_rates = ic->ic_sup_quarter_rates;
++	}
++
++	if ((vap->iv_flags & IEEE80211_F_PUREG) &&
++		IEEE80211_IS_CHAN_ANYG(chan)) {
++		ieee80211_setpuregbasicrates(&ni->ni_rates);
++	}
+ 
+ 	(void) ieee80211_sta_join1(PASS_NODE(ni));
+ }
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -599,6 +599,28 @@
+ 	{ 4, { 2, 4, 11, 22 } },	/* IEEE80211_MODE_TURBO_G (mixed b/g) */
+ };
+ 
++static const struct ieee80211_rateset basicpureg[] = {
++    { 7, {2, 4, 11, 22, 12, 24, 48 } },
++};
++
++/*
++ * Mark basic rates for the 11g rate table based on the pureg setting
++ */
++void
++ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs)
++{
++	int i, j;
++
++	for (i = 0; i < rs->rs_nrates; i++) {
++		rs->rs_rates[i] &= IEEE80211_RATE_VAL;
++		for (j = 0; j < basicpureg[0].rs_nrates; j++)
++			if (basicpureg[0].rs_rates[j] == rs->rs_rates[i]) {
++				rs->rs_rates[i] |= IEEE80211_RATE_BASIC;
++				break;
++			}
++	}
++}
++
+ /*
+  * Mark the basic rates for the 11g rate table based on the
+  * specified mode.  For 11b compatibility we mark only 11b
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -712,6 +712,7 @@
+ void ieee80211_build_sc_ie(struct ieee80211com *);
+ void ieee80211_dfs_action(struct ieee80211com *);
+ void ieee80211_expire_channel_excl_restrictions(struct ieee80211com *);
++void ieee80211_setpuregbasicrates(struct ieee80211_rateset *rs);
+ 
+ /*
+  * Iterate through ic_channels to enumerate all distinct ic_ieee channel numbers.
diff --git a/package/madwifi/patches-testing/302-noise_get.patch b/package/madwifi/patches-testing/302-noise_get.patch
new file mode 100644
index 000000000..8c69ca24f
--- /dev/null
+++ b/package/madwifi/patches-testing/302-noise_get.patch
@@ -0,0 +1,38 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8997,6 +8997,7 @@
+ 			ATH_LONG_CALINTERVAL_SECS : 
+ 			ATH_SHORT_CALINTERVAL_SECS;
+ 	}
++	ic->ic_channoise = ath_hal_get_channel_noise(ah, &(sc->sc_curchan));
+ 
+ 	DPRINTF(sc, ATH_DEBUG_CALIBRATE, "Channel %u [flags=%04x] -- IQ %s.\n",
+ 		sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
+@@ -9052,6 +9053,7 @@
+ 	struct ath_softc *sc = dev->priv;
+ 
+ 	(void) ath_chan_set(sc, ic->ic_curchan);
++	ic->ic_channoise = ath_hal_get_channel_noise(sc->sc_ah, &(sc->sc_curchan));
+ 	/*
+ 	 * If we are returning to our bss channel then mark state
+ 	 * so the next recv'd beacon's TSF will be used to sync the
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -4396,6 +4396,7 @@
+ 	si->isi_state = ni->ni_flags;
+ 	si->isi_authmode = ni->ni_authmode;
+ 	si->isi_rssi = ic->ic_node_getrssi(ni);
++	si->isi_noise = ic->ic_channoise;
+ 	si->isi_capinfo = ni->ni_capinfo;
+ 	si->isi_athflags = ni->ni_ath_flags;
+ 	si->isi_erp = ni->ni_erp;
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -312,6 +312,7 @@
+ 	u_int16_t isi_state;		/* state flags */
+ 	u_int8_t isi_authmode;		/* authentication algorithm */
+ 	u_int8_t isi_rssi;
++	int8_t isi_noise;
+ 	u_int16_t isi_capinfo;		/* capabilities */
+ 	u_int8_t isi_athflags;		/* Atheros capabilities */
+ 	u_int8_t isi_erp;		/* ERP element */
diff --git a/package/madwifi/patches-testing/303-bssid_alloc.patch b/package/madwifi/patches-testing/303-bssid_alloc.patch
new file mode 100644
index 000000000..43e0d6dcf
--- /dev/null
+++ b/package/madwifi/patches-testing/303-bssid_alloc.patch
@@ -0,0 +1,40 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1347,11 +1347,12 @@
+ 			TAILQ_FOREACH(v, &ic->ic_vaps, iv_next)
+ 				id_mask |= (1 << ATH_GET_VAP_ID(v->iv_myaddr));
+ 
+-			for (id = 1; id < ath_maxvaps; id++) {
++			for (id = 0; id < ath_maxvaps; id++) {
+ 				/* Get the first available slot. */
+ 				if ((id_mask & (1 << id)) == 0) {
+ 					ATH_SET_VAP_BSSID(vap->iv_myaddr, id);
+ 					ATH_SET_VAP_BSSID(vap->iv_bssid, id);
++					sc->sc_bclast = id;
+ 					break;
+ 				}
+ 			}
+@@ -1359,7 +1360,12 @@
+ 			EPRINTF(sc, "Unique BSSID requested on HW that does"
+ 				"does not support the necessary features.");
+ 		}
++	} else {
++		/* share the BSSID of the last created VAP */
++		ATH_SET_VAP_BSSID(vap->iv_myaddr, sc->sc_bclast);
++		ATH_SET_VAP_BSSID(vap->iv_bssid, sc->sc_bclast);
+ 	}
++
+ 	avp->av_bslot = -1;
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+ 	atomic_set(&avp->av_beacon_alloc, 0);
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -802,7 +802,7 @@
+ 	} sc_updateslot;			/* slot time update fsm */
+ 	int sc_slotupdate;			/* slot to next advance fsm */
+ 	struct ieee80211vap **sc_bslot;		/* beacon xmit slots */
+-	int sc_bnext;				/* next slot for beacon xmit */
++	int sc_bclast;				/* last used slot for beacon xmit */
+ 
+ 	int sc_beacon_cal;			/* use beacon timer for calibration */
+ 	long unsigned int sc_calinterval_sec;	/* current interval for calibration (in seconds) */
diff --git a/package/madwifi/patches-testing/304-erp_update.patch b/package/madwifi/patches-testing/304-erp_update.patch
new file mode 100644
index 000000000..be64b9537
--- /dev/null
+++ b/package/madwifi/patches-testing/304-erp_update.patch
@@ -0,0 +1,68 @@
+--- a/net80211/ieee80211_beacon.c
++++ b/net80211/ieee80211_beacon.c
+@@ -544,10 +544,10 @@
+ 			vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
+ 		}
+ #endif
+-		if ((ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) && 
++		if ((vap->iv_flags_ext & IEEE80211_FEXT_ERPUPDATE) &&
+ 				(bo->bo_erp != NULL)) {
+ 			(void)ieee80211_add_erp(bo->bo_erp, ic);
+-			ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
++			vap->iv_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
+ 		}
+ 	}
+ 	/* if it is a mode change beacon for dynamic turbo case */
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3384,9 +3384,12 @@
+ 			/* Assume no ERP IE == 11b AP */
+ 			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
+ 				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
++				struct ieee80211vap *tmpvap;
+ 
+ 				ic->ic_flags |= IEEE80211_F_USEPROT;
+-				ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++				TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++					tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++				}
+ 			}
+ 		}
+ 
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1741,8 +1741,12 @@
+ 		}
+ 
+ 		/* Update ERP element if this is first non ERP station */
+-		if (ic->ic_nonerpsta == 1)
+-			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++		if (ic->ic_nonerpsta == 1) {
++			struct ieee80211vap *tmpvap;
++			TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++				tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++			}
++		}
+ 	} else
+ 		ni->ni_flags |= IEEE80211_NODE_ERP;
+ }
+@@ -1945,6 +1949,8 @@
+ 		IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
+ 			"non-ERP station leaves, count now %d", ic->ic_nonerpsta);
+ 		if (ic->ic_nonerpsta == 0) {
++			struct ieee80211vap *tmpvap;
++
+ 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+ 				"%s: disable use of protection\n", __func__);
+ 			ic->ic_flags &= ~IEEE80211_F_USEPROT;
+@@ -1956,7 +1962,9 @@
+ 				ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
+ 				ic->ic_flags &= ~IEEE80211_F_USEBARKER;
+ 			}
+-			ic->ic_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++			TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++				tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++			}
+ 		}
+ 	}
+ }
diff --git a/package/madwifi/patches-testing/305-bssid_mask.patch b/package/madwifi/patches-testing/305-bssid_mask.patch
new file mode 100644
index 000000000..bc02462a3
--- /dev/null
+++ b/package/madwifi/patches-testing/305-bssid_mask.patch
@@ -0,0 +1,13 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8717,6 +8717,10 @@
+ 
+ 	sc->sc_rxbufcur = NULL;
+ 
++	/* configure bssid mask */
++	if (sc->sc_hasbmask)
++		ath_hal_setbssidmask(ah, sc->sc_bssidmask);
++
+ 	bf = STAILQ_FIRST(&sc->sc_rxbuf);
+ 	ath_hal_putrxbuf(ah, bf->bf_daddr);
+ 	ath_hal_rxena(ah);		/* enable recv descriptors */
diff --git a/package/madwifi/patches-testing/306-queue.patch b/package/madwifi/patches-testing/306-queue.patch
new file mode 100644
index 000000000..3341f01b8
--- /dev/null
+++ b/package/madwifi/patches-testing/306-queue.patch
@@ -0,0 +1,42 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8448,8 +8448,6 @@
+ 	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+ 	local_irq_restore(flags);
+ 
+-	netif_wake_queue(dev);
+-
+ 	if (sc->sc_softled)
+ 		ath_led_event(sc, ATH_LED_TX);
+ }
+@@ -8505,8 +8503,6 @@
+ 	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+ 	local_irq_restore(flags);
+ 
+-	netif_wake_queue(dev);
+-
+ 	if (sc->sc_softled)
+ 		ath_led_event(sc, ATH_LED_TX);
+ }
+@@ -8537,7 +8533,9 @@
+ 				STAILQ_FIRST(&sc->sc_cabq->axq_q) ? "not setup" : "empty");
+ 		}
+ 	}
+-	netif_wake_queue(dev);
++
++	if (ath_get_buffers_available(sc) > ATH_TXBUF_MGT_RESERVED)
++		netif_wake_queue(dev);
+ 
+ 	if (sc->sc_softled)
+ 		ath_led_event(sc, ATH_LED_TX);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1116,7 +1116,7 @@
+ 	    (vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
+ 		struct sk_buff *skb1 = NULL;
+ 
+-		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
++		if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
+ 			/* Create a SKB for the BSS to send out. */
+ 			skb1 = skb_copy(skb, GFP_ATOMIC);
+ 			if (skb1)
diff --git a/package/madwifi/patches-testing/307-maxrate.patch b/package/madwifi/patches-testing/307-maxrate.patch
new file mode 100644
index 000000000..a5a1db02f
--- /dev/null
+++ b/package/madwifi/patches-testing/307-maxrate.patch
@@ -0,0 +1,96 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1299,6 +1299,7 @@
+ 	vap->iv_key_set = ath_key_set;
+ 	vap->iv_key_update_begin = ath_key_update_begin;
+ 	vap->iv_key_update_end = ath_key_update_end;
++	vap->iv_maxrateindex = 0;
+ 	if (sc->sc_default_ieee80211_debug) {
+ 		/* User specified defaults for new VAPs were provided, so
+ 		 * use those (only). */
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -838,7 +838,12 @@
+ 	}
+ 	sn->static_rate_ndx = -1;
+ 
+-	sn->num_rates = ni->ni_rates.rs_nrates;
++	if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
++	    || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
++		sn->num_rates = ni->ni_rates.rs_nrates;
++	else
++		sn->num_rates = vap->iv_maxrateindex;
++
+ 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+ 		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+ 		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -291,6 +291,7 @@
+ 	struct ieee80211_spy iv_spy;         		/* IWSPY support */
+ 	struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
+ 	u_int32_t app_filter;				/* filters which management frames are forwarded to app */
++	int iv_maxrateindex;
+ };
+ 
+ /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2873,6 +2873,12 @@
+ 		else
+ 			ic->ic_flags_ext &= ~IEEE80211_FEXT_MARKDFS;
+ 		break;
++	case IEEE80211_PARAM_MAXRATE:
++		if (value > 0)
++			vap->iv_maxrateindex = value;
++		else
++			vap->iv_maxrateindex = 0;
++		break;
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	case IEEE80211_PARAM_DUMPREGS:
+ 		ieee80211_dump_registers(dev, info, w, extra);
+@@ -3211,6 +3217,9 @@
+ 		else
+ 			param[0] = 0;
+ 		break;
++	case IEEE80211_PARAM_MAXRATE:
++		param[0] = vap->iv_maxrateindex;
++		break;
+ 	default:
+ 		return -EOPNOTSUPP;
+ 	}
+@@ -5666,6 +5675,10 @@
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_scanbufs" },
+ 	{ IEEE80211_PARAM_LEAKTXBUFS,
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_leaktxbufs" },
++	{IEEE80211_PARAM_MAXRATE,
++	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
++	{IEEE80211_PARAM_MAXRATE,
++	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
+ 	
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	/*
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -650,6 +650,7 @@
+ 	IEEE80211_PARAM_RESETTXBUFS		= 80,   /* Reset transmit DMA */
+ 	IEEE80211_PARAM_SCANBUFS		= 81,	/* Heap analysis for TX DMA */
+ 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
++	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
+ };
+ 
+ #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -644,6 +644,11 @@
+ 		return;
+ 	}
+ 	sn->static_rate_ndx = -1;
++	if (vap->iv_maxrateindex == 0 || ni->ni_rates.rs_nrates <= 0
++	    || vap->iv_maxrateindex > ni->ni_rates.rs_nrates)
++		sn->num_rates = ni->ni_rates.rs_nrates;
++	else
++		sn->num_rates = vap->iv_maxrateindex;
+ 
+ 	sn->num_rates = ni->ni_rates.rs_nrates;
+ 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
diff --git a/package/madwifi/patches-testing/308-minrate.patch b/package/madwifi/patches-testing/308-minrate.patch
new file mode 100644
index 000000000..8e7b6066a
--- /dev/null
+++ b/package/madwifi/patches-testing/308-minrate.patch
@@ -0,0 +1,112 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -1300,6 +1300,7 @@
+ 	vap->iv_key_update_begin = ath_key_update_begin;
+ 	vap->iv_key_update_end = ath_key_update_end;
+ 	vap->iv_maxrateindex = 0;
++	vap->iv_minrateindex = 0;
+ 	if (sc->sc_default_ieee80211_debug) {
+ 		/* User specified defaults for new VAPs were provided, so
+ 		 * use those (only). */
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -652,6 +652,8 @@
+ 
+ 	sn->num_rates = ni->ni_rates.rs_nrates;
+ 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
++		int idx = x;
++
+ 		sn->rs_rateattempts 	[x] = 0;
+ 		sn->rs_thisprob 	[x] = 0;
+ 		sn->rs_ratesuccess 	[x] = 0;
+@@ -662,8 +664,12 @@
+ 		sn->rs_att_hist 	[x] = 0;
+ 		sn->rs_this_tp 		[x] = 0;
+ 
+-		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+-		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
++		if (vap->iv_minrateindex && (vap->iv_minrateindex <
++				ni->ni_rates.rs_nrates))
++			idx = vap->iv_minrateindex;
++
++		sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
++		sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
+ 		if (sn->rates[x].rix == 0xff) {
+ 			DPRINTF(sc, "%s: %s ignore bogus rix at %d\n",
+ 				dev_info, __func__, x);
+--- a/ath_rate/sample/sample.c
++++ b/ath_rate/sample/sample.c
+@@ -845,8 +845,15 @@
+ 		sn->num_rates = vap->iv_maxrateindex;
+ 
+ 	for (x = 0; x < ni->ni_rates.rs_nrates; x++) {
+-		sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL;
+-		sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate];
++		int idx = x;
++
++		if (vap->iv_minrateindex && vap->iv_minrateindex <
++				ni->ni_rates.rs_nrates)
++			idx = vap->iv_minrateindex;
++
++		sn->rates[x].rate = ni->ni_rates.rs_rates[idx] & IEEE80211_RATE_VAL;
++		sn->rates[x].rix = sc->sc_rixmap[sn->rates[idx].rate];
++
+ 		if (sn->rates[x].rix == 0xff) {
+ 			DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s ignore bogus rix at %u\n",
+ 				dev_info, __func__, x);
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -651,6 +651,7 @@
+ 	IEEE80211_PARAM_SCANBUFS		= 81,	/* Heap analysis for TX DMA */
+ 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
+ 	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
++	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
+ };
+ 
+ #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -292,6 +292,7 @@
+ 	struct ieee80211_app_ie app_ie[IEEE80211_APPIE_NUM_OF_FRAME]; /* app-specified IEs by frame type */
+ 	u_int32_t app_filter;				/* filters which management frames are forwarded to app */
+ 	int iv_maxrateindex;
++	int iv_minrateindex;
+ };
+ 
+ /* Debug functions need the defintion of struct ieee80211vap because iv_debug 
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2879,6 +2879,12 @@
+ 		else
+ 			vap->iv_maxrateindex = 0;
+ 		break;
++	case IEEE80211_PARAM_MINRATE:
++		if (value > 0)
++			vap->iv_minrateindex = value;
++		else
++			vap->iv_minrateindex = 0;
++		break;
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	case IEEE80211_PARAM_DUMPREGS:
+ 		ieee80211_dump_registers(dev, info, w, extra);
+@@ -3220,6 +3226,9 @@
+ 	case IEEE80211_PARAM_MAXRATE:
+ 		param[0] = vap->iv_maxrateindex;
+ 		break;
++	case IEEE80211_PARAM_MINRATE:
++		param[0] = vap->iv_minrateindex;
++		break;
+ 	default:
+ 		return -EOPNOTSUPP;
+ 	}
+@@ -5679,6 +5688,10 @@
+ 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maxrate"},
+ 	{IEEE80211_PARAM_MAXRATE,
+ 	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_maxrate"},
++	{IEEE80211_PARAM_MINRATE,
++	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
++	{IEEE80211_PARAM_MINRATE,
++	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
+ 	
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	/*
diff --git a/package/madwifi/patches-testing/309-performance.patch b/package/madwifi/patches-testing/309-performance.patch
new file mode 100644
index 000000000..ec2208525
--- /dev/null
+++ b/package/madwifi/patches-testing/309-performance.patch
@@ -0,0 +1,215 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -3334,7 +3334,6 @@
+ 	struct ath_softc *sc = dev->priv;
+ 	struct ieee80211_node *ni = NULL;
+ 	struct ath_buf *bf = NULL;
+-	struct ether_header *eh;
+ 	ath_bufhead bf_head;
+ 	struct ath_buf *tbf;
+ 	struct sk_buff *tskb;
+@@ -3349,6 +3348,7 @@
+ 	*/
+ 	int requeue = 0;
+ #ifdef ATH_SUPERG_FF
++	struct ether_header *eh;
+ 	unsigned int pktlen;
+ 	struct ieee80211com *ic = &sc->sc_ic;
+ 	struct ath_txq *txq = NULL;
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -280,7 +280,7 @@
+ 	 * normal vap. */
+ 	if (vap->iv_xrvap && (ni == vap->iv_bss) &&
+ 	    vap->iv_xrvap->iv_sta_assoc) {
+-		struct sk_buff *skb1 = skb_copy(skb, GFP_ATOMIC);
++		struct sk_buff *skb1 = skb_clone(skb, GFP_ATOMIC);
+ 		if (skb1) {
+ 			memset(SKB_CB(skb1), 0, sizeof(struct ieee80211_cb));
+ #ifdef IEEE80211_DEBUG_REFCNT
+@@ -561,7 +561,7 @@
+ 	struct ieee80211_key *key, struct sk_buff *skb, int ismulticast)
+ {
+ 	/* XXX pre-calculate per node? */
+-	int need_headroom = LLC_SNAPFRAMELEN + hdrsize + IEEE80211_ADDR_LEN;
++	int need_headroom = LLC_SNAPFRAMELEN + hdrsize;
+ 	int need_tailroom = 0;
+ #ifdef ATH_SUPERG_FF
+ 	int isff = ATH_FF_MAGIC_PRESENT(skb);
+@@ -603,109 +603,56 @@
+ 				need_tailroom += cip->ic_miclen;
+ 	}
+ 
+-	if (skb_shared(skb)) {
+-		/* Take our own reference to the node in the clone */
+-		ieee80211_ref_node(SKB_NI(skb));
+-		/* Unshare the node, decrementing users in the old skb */
+-		skb = skb_unshare(skb, GFP_ATOMIC);
++	need_headroom -= skb_headroom(skb);
++	if (isff)
++		need_tailroom -= skb_tailroom(skb2);
++	else
++		need_tailroom -= skb_tailroom(skb);
++
++	if (need_headroom < 0)
++		need_headroom = 0;
++	if (need_tailroom < 0)
++		need_tailroom = 0;
++
++	if (skb_cloned(skb) || (need_headroom > 0) ||
++		(!isff && (need_tailroom > 0))) {
++
++		if (pskb_expand_head(skb, need_headroom, need_tailroom, GFP_ATOMIC)) {
++			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
++				"%s: cannot expand storage (tail)\n", __func__);
++			goto error;
++		}
+ 	}
+ 
+ #ifdef ATH_SUPERG_FF
+ 	if (isff) {
+-		if (skb == NULL) {
+-			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-				"%s: cannot unshare for encapsulation\n",
+-				__func__);
+-			vap->iv_stats.is_tx_nobuf++;
+-			ieee80211_dev_kfree_skb(&skb2);
+-
+-			return NULL;
+-		}
++		inter_headroom -= skb_headroom(skb2);
++		if (inter_headroom < 0)
++			inter_headroom = 0;
++		if ((skb_cloned(skb2) ||
++			(inter_headroom > 0) || (need_tailroom > 0))) {
+ 
+-		/* first skb header */
+-		if (skb_headroom(skb) < need_headroom) {
+-			struct sk_buff *tmp = skb;
+-			skb = skb_realloc_headroom(skb, need_headroom);
+-			if (skb == NULL) {
++			if (pskb_expand_head(skb2, inter_headroom,
++				need_tailroom, GFP_ATOMIC)) {
+ 				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-					"%s: cannot expand storage (head1)\n",
+-					__func__);
+-				vap->iv_stats.is_tx_nobuf++;
+-				ieee80211_dev_kfree_skb(&skb2);
+-				return NULL;
+-			} else
+-				ieee80211_skb_copy_noderef(tmp, skb);
+-			ieee80211_dev_kfree_skb(&tmp);
+-			/* NB: cb[] area was copied, but not next ptr. must do that
+-			 *     prior to return on success. */
+-		}
+-
+-		/* second skb with header and tail adjustments possible */
+-		if (skb_tailroom(skb2) < need_tailroom) {
+-			int n = 0;
+-			if (inter_headroom > skb_headroom(skb2))
+-				n = inter_headroom - skb_headroom(skb2);
+-			if (pskb_expand_head(skb2, n,
+-			    need_tailroom - skb_tailroom(skb2), GFP_ATOMIC)) {
+-				ieee80211_dev_kfree_skb(&skb2);
+-				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-					"%s: cannot expand storage (tail2)\n",
+-					__func__);
+-				vap->iv_stats.is_tx_nobuf++;
+-				/* this shouldn't happen, but don't send first ff either */
+-				ieee80211_dev_kfree_skb(&skb);
++					"%s: cannot expand storage (tail)\n", __func__);
++				goto error;
+ 			}
+-		} else if (skb_headroom(skb2) < inter_headroom) {
+-			struct sk_buff *tmp = skb2;
+-
+-			skb2 = skb_realloc_headroom(skb2, inter_headroom);
+-			if (skb2 == NULL) {
+-				IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-					"%s: cannot expand storage (head2)\n",
+-					__func__);
+-				vap->iv_stats.is_tx_nobuf++;
+-				/* this shouldn't happen, but don't send first ff either */
+-				ieee80211_dev_kfree_skb(&skb);
+-				skb = NULL;
+-			} else
+-				ieee80211_skb_copy_noderef(tmp, skb);
+-			ieee80211_dev_kfree_skb(&tmp);
+ 		}
+-		if (skb) {
+-			skb->next = skb2;
+-		}
+-		return skb;
++		skb->next = skb2;
+ 	}
+ #endif /* ATH_SUPERG_FF */
+-	if (skb == NULL) {
+-		IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-			"%s: cannot unshare for encapsulation\n", __func__);
+-		vap->iv_stats.is_tx_nobuf++;
+-	} else if (skb_tailroom(skb) < need_tailroom) {
+-		int n = 0;
+-		if (need_headroom > skb_headroom(skb))
+-			n = need_headroom - skb_headroom(skb);
+-		if (pskb_expand_head(skb, n, need_tailroom - 
+-					skb_tailroom(skb), GFP_ATOMIC)) {
+-			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-				"%s: cannot expand storage (tail)\n", __func__);
+-			vap->iv_stats.is_tx_nobuf++;
+-			ieee80211_dev_kfree_skb(&skb);
+-		}
+-	} else if (skb_headroom(skb) < need_headroom) {
+-		struct sk_buff *tmp = skb;
+-		skb = skb_realloc_headroom(skb, need_headroom);
+-		/* Increment reference count after copy */
+-		if (skb == NULL) {
+-			IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+-				"%s: cannot expand storage (head)\n", __func__);
+-			vap->iv_stats.is_tx_nobuf++;
+-		} else
+-			ieee80211_skb_copy_noderef(tmp, skb);
+-		ieee80211_dev_kfree_skb(&tmp);
+-	}
+ 
+ 	return skb;
++
++error:
++	vap->iv_stats.is_tx_nobuf++;
++	ieee80211_dev_kfree_skb(&skb);
++#ifdef ATH_SUPERG_FF
++	if (skb2)
++		ieee80211_dev_kfree_skb(&skb2);
++#endif
++	return NULL;
+ }
+ 
+ #define	KEY_UNDEFINED(k)	((k).wk_cipher == &ieee80211_cipher_none)
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -713,7 +713,7 @@
+ 			/* ether_type must be length as FF frames are always LLC/SNAP encap'd */ 
+ 			frame_len = ntohs(eh_tmp->ether_type); 
+ 
+-			skb1 = skb_copy(skb, GFP_ATOMIC);
++			skb1 = skb_clone(skb, GFP_ATOMIC);
+ 			if (skb1 == NULL)
+ 				goto err;
+ 			ieee80211_skb_copy_noderef(skb, skb1);
+@@ -1118,7 +1118,7 @@
+ 
+ 		if (ETHER_IS_MULTICAST(eh->ether_dhost) && !netif_queue_stopped(dev)) {
+ 			/* Create a SKB for the BSS to send out. */
+-			skb1 = skb_copy(skb, GFP_ATOMIC);
++			skb1 = skb_clone(skb, GFP_ATOMIC);
+ 			if (skb1)
+ 				SKB_NI(skb1) = ieee80211_ref_node(vap->iv_bss); 
+ 		}
+@@ -2265,7 +2265,7 @@
+ 	if (filter_type && ((vap->app_filter & filter_type) == filter_type)) {
+ 		struct sk_buff *skb1;
+ 
+-		skb1 = skb_copy(skb, GFP_ATOMIC);
++		skb1 = skb_clone(skb, GFP_ATOMIC);
+ 		if (skb1 == NULL)
+ 			return;
+ 		/* We duplicate the reference after skb_copy */
diff --git a/package/madwifi/patches-testing/310-minstrel_sampling.patch b/package/madwifi/patches-testing/310-minstrel_sampling.patch
new file mode 100644
index 000000000..b7f55d500
--- /dev/null
+++ b/package/madwifi/patches-testing/310-minstrel_sampling.patch
@@ -0,0 +1,84 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8110,6 +8110,7 @@
+ 		ath_hal_setupxtxdesc(sc->sc_ah, ds, mrr.rate1, mrr.retries1,
+ 				     mrr.rate2, mrr.retries2,
+ 				     mrr.rate3, mrr.retries3);
++		bf->rcflags = mrr.privflags;
+ 	}
+ 
+ #ifndef ATH_SUPERG_FF
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -454,6 +454,7 @@
+ 	u_int16_t bf_flags;				/* tx descriptor flags */
+ 	u_int64_t bf_tsf;
+ 	int16_t bf_channoise;
++	unsigned int rcflags;
+ #ifdef ATH_SUPERG_FF
+ 	/* XXX: combine this with bf_skbaddr if it ever changes to accommodate
+ 	 *      multiple segments.
+--- a/ath_rate/minstrel/minstrel.c
++++ b/ath_rate/minstrel/minstrel.c
+@@ -341,18 +341,21 @@
+ 		if (sn->static_rate_ndx >= 0) {
+ 			    ndx = sn->static_rate_ndx;
+ 		} else {
++			int delta;
++
+ 			sn->packet_count++;
+ 			sn->random_n = (sn->a * sn->random_n) + sn->b;
+ 			offset = sn->random_n & 0xf;
+ 
+-			if ((((100 * sn->sample_count) / sn->packet_count) < 
+-					 ath_lookaround_rate) && 
+-					(offset < 2)) {
++			delta = (sn->packet_count * ath_lookaround_rate / 100) - sn->sample_count;
++			if ((delta > 0) && (offset < 2)) {
+ 				sn->sample_count++;
+ 				sn->is_sampling = 1;
+ 				if (sn->packet_count >= 10000) {
+ 					sn->sample_count = 0;
+ 					sn->packet_count = 0;
++				} else if (delta > sn->num_rates * 2) {
++					sn->sample_count += ((delta - sn->num_rates * 2) * ath_lookaround_rate) / 100;
+ 				}
+ 
+ 				/* Don't look for slowest rate (i.e. slowest
+@@ -420,11 +423,14 @@
+ 		if (sn->num_rates <= 0)
+ 			return;
+ 
++		mrr->privflags = sn->is_sampling;
+ 		if (sn->is_sampling) {
+ 			sn->is_sampling = 0;
+-			if (sn->rs_sample_rate_slower)
++			if (sn->rs_sample_rate_slower) {
+ 				rc1 = sn->rs_sample_rate;
+-			else
++				if (sn->sample_count > 0)
++					sn->sample_count--;
++			} else
+ 				rc1 = sn->max_tp_rate;
+ 		} else {
+ 			rc1 = sn->max_tp_rate2;
+@@ -552,6 +558,9 @@
+ 		if (tries <= tries1)
+ 			return;
+ 
++		if (bf->rcflags)
++			sn->sample_count++;
++
+ 		if  (tries2 < 0)
+ 			return;
+ 		tries = tries - tries1;
+--- a/net80211/ieee80211_rate.h
++++ b/net80211/ieee80211_rate.h
+@@ -87,6 +87,7 @@
+ 	int retries2;
+ 	int rate3;
+ 	int retries3;
++	int privflags;
+ };
+ 
+ struct ieee80211_rate_ops {
diff --git a/package/madwifi/patches-testing/311-protmode_trigger.patch b/package/madwifi/patches-testing/311-protmode_trigger.patch
new file mode 100644
index 000000000..2f462b9a6
--- /dev/null
+++ b/package/madwifi/patches-testing/311-protmode_trigger.patch
@@ -0,0 +1,135 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -347,7 +347,9 @@
+ 			IEEE80211_MS_TO_TU(IEEE80211_BMISSTHRESH_DEFAULT_MS), 
+ 			ic->ic_lintval), ic->ic_lintval);
+ 	}
+-		
++	ic->ic_protmode_timeout = IEEE80211_PROTMODE_TIMEOUT;
++	ic->ic_protmode_rssi = IEEE80211_PROTMODE_RSSITHR;
++
+ 	IEEE80211_LOCK_INIT(ic, "ieee80211com");
+ 	IEEE80211_VAPS_LOCK_INIT(ic, "ieee80211com_vaps");
+ 	TAILQ_INIT(&ic->ic_vaps);
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3382,14 +3382,18 @@
+ 			IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) {
+ 
+ 			/* Assume no ERP IE == 11b AP */
+-			if ((!has_erp || (has_erp && (scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
+-				!(ic->ic_flags & IEEE80211_F_USEPROT)) {
++			if ((!has_erp || (has_erp &&
++				(scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) &&
++				(rssi > ic->ic_protmode_rssi)) {
+ 				struct ieee80211vap *tmpvap;
+ 
+-				ic->ic_flags |= IEEE80211_F_USEPROT;
+-				TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
+-					tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++				if (!(ic->ic_flags & IEEE80211_F_USEPROT)) {
++					ic->ic_flags |= IEEE80211_F_USEPROT;
++					TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++						tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++					}
+ 				}
++				ic->ic_protmode_lasttrig = jiffies;
+ 			}
+ 		}
+ 
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -652,6 +652,8 @@
+ 	IEEE80211_PARAM_LEAKTXBUFS		= 82,	/* Leak tx buffers */
+ 	IEEE80211_PARAM_MAXRATE			= 83,	/* Maximum rate (by table index) */
+ 	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
++	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
++	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
+ };
+ 
+ #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -138,6 +138,9 @@
+ 
+ #define	IEEE80211_APPIE_MAX	1024
+ 
++#define IEEE80211_PROTMODE_RSSITHR	15	/* default rssi threshold for protection mode trigger */
++#define IEEE80211_PROTMODE_TIMEOUT	30	/* timeout for keeping protection mode alive */
++
+ #define IEEE80211_PWRCONSTRAINT_VAL(ic) \
+ 	(((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \
+ 	    (ic)->ic_bsschan->ic_maxregpower - (ic)->ic_curchanmaxpwr : 0)
+@@ -335,6 +338,9 @@
+ 	u_int16_t ic_newtxpowlimit; 		/* tx power limit to change to (in 0.5 dBm) */
+ 	u_int16_t ic_uapsdmaxtriggers; 		/* max triggers that could arrive */
+ 	u_int8_t ic_coverageclass; 		/* coverage class */
++	u_int8_t ic_protmode_rssi;			/* rssi threshold for protection mode */
++	u_int64_t ic_protmode_lasttrig;		/* last trigger for protection mode */
++	u_int16_t ic_protmode_timeout;		/* protection mode timeout */
+ 
+ 	/* Channel state:
+ 	 *
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2336,6 +2336,12 @@
+ 	case IEEE80211_PARAM_RSSI_EWMA:
+ 		ic->ic_rssi_ewma = value;
+ 		break;
++	case IEEE80211_PARAM_PROTMODE_TIMEOUT:
++		ic->ic_protmode_timeout = value;
++		break;
++	case IEEE80211_PARAM_PROTMODE_RSSI:
++		ic->ic_protmode_rssi = value;
++		break;
+ 	case IEEE80211_PARAM_MCASTCIPHER:
+ 		if ((vap->iv_caps & cipher2cap(value)) == 0 &&
+ 		    !ieee80211_crypto_available(vap, value))
+@@ -2992,6 +2998,12 @@
+ 	case IEEE80211_PARAM_RSSI_EWMA:
+ 		param[0] = ic->ic_rssi_ewma;
+ 		break;
++	case IEEE80211_PARAM_PROTMODE_TIMEOUT:
++		param[0] = ic->ic_protmode_timeout;
++		break;
++	case IEEE80211_PARAM_PROTMODE_RSSI:
++		param[0] = ic->ic_protmode_rssi;
++		break;
+ 	case IEEE80211_PARAM_MCASTCIPHER:
+ 		param[0] = rsn->rsn_mcastcipher;
+ 		break;
+@@ -5384,6 +5396,14 @@
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protmode" },
+ 	{ IEEE80211_PARAM_PROTMODE,
+ 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protmode" },
++	{ IEEE80211_PARAM_PROTMODE_RSSI,
++	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "protrssi" },
++	{ IEEE80211_PARAM_PROTMODE_RSSI,
++	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_protrssi" },
++	{ IEEE80211_PARAM_PROTMODE_TIMEOUT,
++	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prottime" },
++	{ IEEE80211_PARAM_PROTMODE_TIMEOUT,
++	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_prottime" },
+ 	{ IEEE80211_PARAM_MCASTCIPHER,
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcastcipher" },
+ 	{ IEEE80211_PARAM_MCASTCIPHER,
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1591,6 +1591,17 @@
+ 
+ 	ieee80211_scan_timeout(ic);
+ 	ieee80211_timeout_stations(&ic->ic_sta);
++	if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
++		(ic->ic_protmode_lasttrig + ic->ic_protmode_timeout * HZ <
++			jiffies)) {
++		struct ieee80211vap *tmpvap;
++
++		/* expire protection mode */
++		ic->ic_flags &= ~IEEE80211_F_USEPROT;
++		TAILQ_FOREACH(tmpvap, &ic->ic_vaps, iv_next) {
++			tmpvap->iv_flags_ext |= IEEE80211_FEXT_ERPUPDATE;
++		}
++	}
+ 
+ 	mod_timer(&ic->ic_inact, jiffies + IEEE80211_INACT_WAIT * HZ);
+ }
diff --git a/package/madwifi/patches-testing/312-ack_cts_rate.patch b/package/madwifi/patches-testing/312-ack_cts_rate.patch
new file mode 100644
index 000000000..42bb4c171
--- /dev/null
+++ b/package/madwifi/patches-testing/312-ack_cts_rate.patch
@@ -0,0 +1,40 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -10890,8 +10890,13 @@
+ 				break;
+ #endif
+ 			case ATH_ACKRATE:
+-				sc->sc_ackrate = val;
+-				ath_set_ack_bitrate(sc, sc->sc_ackrate);
++				if (val == -1)
++					sc->sc_ackrate_override = 0;
++				else {
++					sc->sc_ackrate_override = 1;
++					sc->sc_ackrate = val;
++					ath_set_ack_bitrate(sc, sc->sc_ackrate);
++				}
+ 				break;
+ 			case ATH_RP:
+ 				ath_rp_record(sc,
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -698,6 +698,7 @@
+ 	unsigned int	sc_hasclrkey:1;		/* CLR key supported */
+ 	unsigned int	sc_stagbeacons:1;	/* use staggered beacons */
+ 	unsigned int	sc_dfswait:1;		/* waiting on channel for radar detect */
++	unsigned int	sc_ackrate_override:1;	/* override ack rate */
+ 	unsigned int	sc_ackrate:1;		/* send acks at high bitrate */
+ 	unsigned int	sc_dfs_cac:1;		/* waiting on channel for radar detect */
+ 	unsigned int	sc_hasintmit:1;		/* Interference mitigation */
+--- a/ath/if_ath_hal_extensions.c
++++ b/ath/if_ath_hal_extensions.c
+@@ -129,6 +129,9 @@
+ int
+ ath_set_ack_bitrate(struct ath_softc *sc, int high)
+ {
++	if (!sc->sc_ackrate_override)
++		return 0;
++
+ 	if (ar_device(sc->devid) == 5212 || ar_device(sc->devid) == 5213) {
+ 		/* set ack to be sent at low bit-rate */
+ 		u_int32_t v = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
diff --git a/package/madwifi/patches-testing/313-reset_channelchange.patch b/package/madwifi/patches-testing/313-reset_channelchange.patch
new file mode 100644
index 000000000..42d18ece0
--- /dev/null
+++ b/package/madwifi/patches-testing/313-reset_channelchange.patch
@@ -0,0 +1,18 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8866,14 +8866,7 @@
+ 			hchan.channel,
+ 			jiffies);
+ 
+-		/* ath_hal_reset with chanchange = AH_TRUE doesn't seem to
+-		 * completely reset the state of the card.  According to
+-		 * reports from ticket #1106, kismet and aircrack people they
+-		 * needed to do the reset with chanchange = AH_FALSE in order
+-		 * to receive traffic when peforming high velocity channel
+-		 * changes. */
+-		if (!ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_TRUE, &status)   ||
+-		    !ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_FALSE, &status)) {
++		if (!ath_hw_reset(sc, sc->sc_opmode, &hchan, AH_TRUE, &status)) {
+ 			EPRINTF(sc, "Unable to reset channel %u (%u MHz) "
+ 				"flags 0x%x '%s' (HAL status %u)\n",
+ 				ieee80211_chan2ieee(ic, chan), chan->ic_freq,
diff --git a/package/madwifi/patches-testing/314-wisoc_softled.patch b/package/madwifi/patches-testing/314-wisoc_softled.patch
new file mode 100644
index 000000000..ca5ffdce4
--- /dev/null
+++ b/package/madwifi/patches-testing/314-wisoc_softled.patch
@@ -0,0 +1,11 @@
+--- a/ath/if_ath_ahb.c
++++ b/ath/if_ath_ahb.c
+@@ -245,6 +245,8 @@
+ 	num_activesc++;
+ 	/* Ready to process interrupts */
+ 
++	sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */
++	sc->aps_sc.sc_ledpin = config->board->sysLedGpio;
+ 	sc->aps_sc.sc_invalid = 0;
+ 	return 0;
+ 
diff --git a/package/madwifi/patches-testing/315-scanlist.patch b/package/madwifi/patches-testing/315-scanlist.patch
new file mode 100644
index 000000000..0ae0ed010
--- /dev/null
+++ b/package/madwifi/patches-testing/315-scanlist.patch
@@ -0,0 +1,876 @@
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -318,147 +318,6 @@
+ #undef ISPROBE
+ }
+ 
+-static struct ieee80211_channel *
+-find11gchannel(struct ieee80211com *ic, int i, int freq)
+-{
+-	struct ieee80211_channel *c;
+-	int j;
+-
+-	/*
+-	 * The normal ordering in the channel list is b channel
+-	 * immediately followed by g so optimize the search for
+-	 * this.  We'll still do a full search just in case.
+-	 */
+-	for (j = i+1; j < ic->ic_nchans; j++) {
+-		c = &ic->ic_channels[j];
+-		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+-			return c;
+-	}
+-	for (j = 0; j < i; j++) {
+-		c = &ic->ic_channels[j];
+-		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
+-			return c;
+-	}
+-	return NULL;
+-}
+-static const u_int chanflags[] = {
+-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
+-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
+-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
+-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
+-	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
+-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
+-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
+-	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
+-};
+-
+-static void
+-add_channels(struct ieee80211com *ic,
+-	struct ieee80211_scan_state *ss,
+-	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
+-{
+-	struct ieee80211_channel *c, *cg;
+-	u_int modeflags;
+-	int i;
+-
+-	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+-	modeflags = chanflags[mode];
+-	for (i = 0; i < nfreq; i++) {
+-		c = ieee80211_find_channel(ic, freq[i], modeflags);
+-		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
+-			continue;
+-		if (mode == IEEE80211_MODE_AUTO) {
+-			/*
+-			 * XXX special-case 11b/g channels so we select
+-			 *     the g channel if both are present.
+-			 */
+-			if (IEEE80211_IS_CHAN_B(c) &&
+-			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+-				c = cg;
+-		}
+-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-			break;
+-		ss->ss_chans[ss->ss_last++] = c;
+-	}
+-}
+-
+-static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */
+-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
+-static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
+-{ 5170, 5190, 5210, 5230 };
+-static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
+-{ 2412, 2437, 2462, 2442, 2472 };
+-static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
+-{ 5745, 5765, 5785, 5805, 5825 };
+-static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */
+-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
+-static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
+-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
+-static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
+-{ 2484 };
+-static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
+-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
+-static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
+-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
+-#ifdef ATH_TURBO_SCAN
+-static const u_int16_t rcl5[] =		/* 3 static turbo channels */
+-{ 5210, 5250, 5290 };
+-static const u_int16_t rcl6[] =		/* 2 static turbo channels */
+-{ 5760, 5800 };
+-static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
+-{ 5540, 5580, 5620, 5660 };
+-static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
+-{ 2437 };
+-static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
+-{ 5200, 5240, 5280, 5765, 5805 };
+-#endif /* ATH_TURBO_SCAN */
+-
+-struct scanlist {
+-	u_int16_t	mode;
+-	u_int16_t	count;
+-	const u_int16_t	*list;
+-};
+-
+-#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
+-#define	X(a)	.count = sizeof(a)/sizeof(a[0]), .list = a
+-
+-static const struct scanlist staScanTable[] = {
+-	{ IEEE80211_MODE_11B,   		X(rcl3) },
+-	{ IEEE80211_MODE_11A,   		X(rcl1) },
+-	{ IEEE80211_MODE_11A,   		X(rcl2) },
+-	{ IEEE80211_MODE_11B,   		X(rcl8) },
+-	{ IEEE80211_MODE_11B,   		X(rcl9) },
+-	{ IEEE80211_MODE_11A,   		X(rcl4) },
+-#ifdef ATH_TURBO_SCAN
+-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5) },
+-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6) },
+-	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
+-	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
+-#endif /* ATH_TURBO_SCAN */
+-	{ IEEE80211_MODE_11A,			X(rcl7) },
+-	{ IEEE80211_MODE_11B,			X(rcl10) },
+-	{ IEEE80211_MODE_11A,			X(rcl11) },
+-#ifdef ATH_TURBO_SCAN
+-	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
+-#endif /* ATH_TURBO_SCAN */
+-	{ .list = NULL }
+-};
+-
+-#undef X
+-
+-static int
+-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
+-{
+-	int i;
+-
+-	for (; scan->list != NULL; scan++) {
+-		for (i = 0; i < scan->count; i++)
+-			if (scan->list[i] == c->ic_freq)
+-				return 1;
+-	}
+-	return 0;
+-}
+-
+ /*
+  * Start a station-mode scan by populating the channel list.
+  */
+@@ -467,81 +326,11 @@
+ {
+ 	struct ieee80211com *ic = vap->iv_ic;
+ 	struct sta_table *st = ss->ss_priv;
+-	const struct scanlist *scan;
+-	enum ieee80211_phymode mode;
+-	struct ieee80211_channel *c;
+-	int i;
+ 
+ 	ss->ss_last = 0;
+-	/*
+-	 * Use the table of ordered channels to construct the list
+-	 * of channels for scanning.  Any channels in the ordered
+-	 * list not in the master list will be discarded.
+-	 */
+-	for (scan = staScanTable; scan->list != NULL; scan++) {
+-		mode = scan->mode;
+-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-			/*
+-			 * If a desired mode was specified, scan only 
+-			 * channels that satisfy that constraint.
+-			 */
+-			if (vap->iv_des_mode != mode) {
+-				/*
+-				 * The scan table marks 2.4Ghz channels as b
+-				 * so if the desired mode is 11g, then use
+-				 * the 11b channel list but upgrade the mode.
+-				 */
+-				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
+-				    mode != IEEE80211_MODE_11B)
+-					continue;
+-				mode = IEEE80211_MODE_11G;	/* upgrade */
+-			}
+-		} else {
+-			/*
+-			 * This lets ieee80211_scan_add_channels
+-			 * upgrade an 11b channel to 11g if available.
+-			 */
+-			if (mode == IEEE80211_MODE_11B)
+-				mode = IEEE80211_MODE_AUTO;
+-		}
+-		/* XR does not operate on turbo channels */
+-		if ((vap->iv_flags & IEEE80211_F_XR) &&
+-		    (mode == IEEE80211_MODE_TURBO_A ||
+-		     mode == IEEE80211_MODE_TURBO_G))
+-			continue;
+-		/*
+-		 * Add the list of the channels; any that are not
+-		 * in the master channel list will be discarded.
+-		 */
+-		add_channels(ic, ss, mode, scan->list, scan->count);
+-	}
+-
+-	/*
+-	 * Add the channels from the ic (from HAL) that are not present
+-	 * in the staScanTable.
+-	 */
+-	for (i = 0; i < ic->ic_nchans; i++) {
+-		c = &ic->ic_channels[i];
+-		/*
+-		 * scan dynamic turbo channels in normal mode.
+-		 */
+-		if (IEEE80211_IS_CHAN_DTURBO(c))
+-			continue;
+-		mode = ieee80211_chan2mode(c);
+-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-			/*
+-			 * If a desired mode was specified, scan only 
+-			 * channels that satisfy that constraint.
+-			 */
+-			if (vap->iv_des_mode != mode)
+-				continue;
+-
+-		}
+-		if (!checktable(staScanTable, c))
+-			ss->ss_chans[ss->ss_last++] = c;
+-	}
+-
++	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
+ 	ss->ss_next = 0;
++
+ 	/* XXX tunables */
+ 	/* 
+ 	 * The scanner will stay on station for ss_maxdwell ms (using a 
+@@ -750,17 +539,7 @@
+ 	fail = 0;
+ 	if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan)))
+ 		fail |= 0x01;
+-	/*
+-	 * NB: normally the desired mode is used to construct
+-	 * the channel list, but it's possible for the scan
+-	 * cache to include entries for stations outside this
+-	 * list so we check the desired mode here to weed them
+-	 * out.
+-	 */
+-	if (vap->iv_des_mode != IEEE80211_MODE_AUTO &&
+-	    (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
+-	    chanflags[vap->iv_des_mode])
+-		fail |= 0x01;
++
+ 	if (vap->iv_opmode == IEEE80211_M_IBSS) {
+ 		if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
+ 			fail |= 0x02;
+@@ -1175,78 +954,6 @@
+ 	.scan_default		= ieee80211_sta_join,
+ };
+ 
+-/*
+- * Start an adhoc-mode scan by populating the channel list.
+- */
+-static int
+-adhoc_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+-{
+-	struct ieee80211com *ic = vap->iv_ic;
+-	struct sta_table *st = ss->ss_priv;
+-	const struct scanlist *scan;
+-	enum ieee80211_phymode mode;
+-
+-	ss->ss_last = 0;
+-	/*
+-	 * Use the table of ordered channels to construct the list
+-	 * of channels for scanning.  Any channels in the ordered
+-	 * list not in the master list will be discarded.
+-	 */
+-	for (scan = staScanTable; scan->list != NULL; scan++) {
+-		mode = scan->mode;
+-		if (vap->iv_des_mode != IEEE80211_MODE_AUTO) {
+-			/*
+-			 * If a desired mode was specified, scan only 
+-			 * channels that satisfy that constraint.
+-			 */
+-			if (vap->iv_des_mode != mode) {
+-				/*
+-				 * The scan table marks 2.4Ghz channels as b
+-				 * so if the desired mode is 11g, then use
+-				 * the 11b channel list but upgrade the mode.
+-				 */
+-				if (vap->iv_des_mode != IEEE80211_MODE_11G ||
+-				    mode != IEEE80211_MODE_11B)
+-					continue;
+-				mode = IEEE80211_MODE_11G;	/* upgrade */
+-			}
+-		} else {
+-			/*
+-			 * This lets ieee80211_scan_add_channels
+-			 * upgrade an 11b channel to 11g if available.
+-			 */
+-			if (mode == IEEE80211_MODE_11B)
+-				mode = IEEE80211_MODE_AUTO;
+-		}
+-		/* XR does not operate on turbo channels */
+-		if ((vap->iv_flags & IEEE80211_F_XR) &&
+-		    (mode == IEEE80211_MODE_TURBO_A ||
+-		     mode == IEEE80211_MODE_TURBO_G))
+-			continue;
+-		/*
+-		 * Add the list of the channels; any that are not
+-		 * in the master channel list will be discarded.
+-		 */
+-		add_channels(ic, ss, mode, scan->list, scan->count);
+-	}
+-	ss->ss_next = 0;
+-	/* XXX tunables */
+-	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
+-	ss->ss_maxdwell = msecs_to_jiffies(200);	/* 200ms */
+-
+-#ifdef IEEE80211_DEBUG
+-	if (ieee80211_msg_scan(vap)) {
+-		printk("%s: scan set ", vap->iv_dev->name);
+-		ieee80211_scan_dump_channels(ss);
+-		printk(" dwell min %ld max %ld\n",
+-			ss->ss_mindwell, ss->ss_maxdwell);
+-	}
+-#endif /* IEEE80211_DEBUG */
+-
+-	st->st_newscan = 1;
+-
+-	return 0;
+-}
+ 
+ /*
+  * Select a channel to start an adhoc network on.
+@@ -1412,7 +1119,7 @@
+ 	.scan_name		= "default",
+ 	.scan_attach		= sta_attach,
+ 	.scan_detach		= sta_detach,
+-	.scan_start		= adhoc_start,
++	.scan_start		= sta_start,
+ 	.scan_restart		= sta_restart,
+ 	.scan_cancel		= sta_cancel,
+ 	.scan_end		= adhoc_pick_bss,
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -292,6 +292,11 @@
+ 			("channel with bogus ieee number %u", c->ic_ieee));
+ 		setbit(ic->ic_chan_avail, c->ic_ieee);
+ 
++		if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)
++			c->ic_scanflags |= IEEE80211_NOSCAN_SET;
++		else
++			c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
++
+ 		/* Identify mode capabilities. */
+ 		if (IEEE80211_IS_CHAN_A(c))
+ 			ic->ic_modecaps |= 1 << IEEE80211_MODE_11A;
+--- a/net80211/_ieee80211.h
++++ b/net80211/_ieee80211.h
+@@ -132,6 +132,11 @@
+ 	IEEE80211_SCAN_FIRST	= 2,	/* take first suitable candidate */
+ };
+ 
++enum ieee80211_scanflags {
++	IEEE80211_NOSCAN_DEFAULT = (1 << 0),
++	IEEE80211_NOSCAN_SET     = (1 << 1),
++};
++
+ /*
+  * Channels are specified by frequency and attributes.
+  */
+@@ -142,6 +147,7 @@
+ 	int8_t ic_maxregpower;	/* maximum regulatory tx power in dBm */
+ 	int8_t ic_maxpower;	/* maximum tx power in dBm */
+ 	int8_t ic_minpower;	/* minimum tx power in dBm */
++	u_int8_t ic_scanflags;
+ };
+ 
+ #define	IEEE80211_CHAN_MAX	255
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -556,6 +556,7 @@
+ #define	IEEE80211_IOCTL_WDSADDMAC	(SIOCIWFIRSTPRIV+26)
+ #define	IEEE80211_IOCTL_WDSDELMAC	(SIOCIWFIRSTPRIV+28)
+ #define	IEEE80211_IOCTL_KICKMAC		(SIOCIWFIRSTPRIV+30)
++#define	IEEE80211_IOCTL_SETSCANLIST	(SIOCIWFIRSTPRIV+31)
+ 
+ enum {
+ 	IEEE80211_WMMPARAMS_CWMIN       = 1,
+--- a/net80211/ieee80211_scan_ap.c
++++ b/net80211/ieee80211_scan_ap.c
+@@ -200,131 +200,7 @@
+ 
+ static int ap_flush(struct ieee80211_scan_state *);
+ static void action_tasklet(IEEE80211_TQUEUE_ARG);
+-static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, 
+-		int i, int freq);
+ 
+-static const u_int chanflags[] = {
+-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_AUTO */
+-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
+-	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
+-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
+-	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
+-	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode 
+-							      * look for AP in 
+-							      * normal channel 
+-							      */
+-	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
+-	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
+-};
+-
+-static const u_int16_t rcl1[] =		/* 8 FCC channel: 52, 56, 60, 64, 
+-					 *                36, 40, 44, 48 */
+-{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
+-static const u_int16_t rcl2[] =		/* 4 MKK channels: 34, 38, 42, 46 */
+-{ 5170, 5190, 5210, 5230 };
+-static const u_int16_t rcl3[] =		/* 2.4Ghz ch: 1,6,11,7,13 */
+-{ 2412, 2437, 2462, 2442, 2472 };
+-static const u_int16_t rcl4[] =		/* 5 FCC channel: 149, 153, 161, 165 */
+-{ 5745, 5765, 5785, 5805, 5825 };
+-static const u_int16_t rcl7[] =		/* 11 ETSI channel: 100, 104, 108, 112,
+-					 *                  116, 120, 124, 128, 
+-					 *                  132, 136, 140 */
+-{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
+-static const u_int16_t rcl8[] =		/* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
+-{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
+-static const u_int16_t rcl9[] =		/* 2.4Ghz ch: 14 */
+-{ 2484 };
+-static const u_int16_t rcl10[] =	/* Added Korean channels 2312-2372 */
+-{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
+-static const u_int16_t rcl11[] =	/* Added Japan channels in 4.9/5.0 spectrum */
+-{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
+-#ifdef ATH_TURBO_SCAN
+-static const u_int16_t rcl5[] =		/* 3 static turbo channels */
+-{ 5210, 5250, 5290 };
+-static const u_int16_t rcl6[] =		/* 2 static turbo channels */
+-{ 5760, 5800 };
+-static const u_int16_t rcl6x[] =		/* 4 FCC3 turbo channels */
+-{ 5540, 5580, 5620, 5660 };
+-static const u_int16_t rcl12[] =		/* 2.4Ghz Turbo channel 6 */
+-{ 2437 };
+-static const u_int16_t rcl13[] =		/* dynamic Turbo channels */
+-{ 5200, 5240, 5280, 5765, 5805 };
+-#endif /* ATH_TURBO_SCAN */
+-
+-struct scanlist {
+-	u_int16_t	mode;
+-	u_int16_t	count;
+-	const u_int16_t	*list;
+-};
+-
+-#define	IEEE80211_MODE_TURBO_STATIC_A	IEEE80211_MODE_MAX
+-#define	X(a)	.count = ARRAY_SIZE(a), .list = a
+-
+-static const struct scanlist staScanTable[] = {
+-	{ IEEE80211_MODE_11B,   		X(rcl3)  },
+-	{ IEEE80211_MODE_11A,   		X(rcl1)  },
+-	{ IEEE80211_MODE_11A,   		X(rcl2)  },
+-	{ IEEE80211_MODE_11B,   		X(rcl8)  },
+-	{ IEEE80211_MODE_11B,   		X(rcl9)  },
+-	{ IEEE80211_MODE_11A,   		X(rcl4)  },
+-#ifdef ATH_TURBO_SCAN
+-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl5)  },
+-	{ IEEE80211_MODE_TURBO_STATIC_A,	X(rcl6)  },
+-	{ IEEE80211_MODE_TURBO_A,		X(rcl6x) },
+-	{ IEEE80211_MODE_TURBO_A,		X(rcl13) },
+-#endif /* ATH_TURBO_SCAN */
+-	{ IEEE80211_MODE_11A,			X(rcl7)  },
+-	{ IEEE80211_MODE_11B,			X(rcl10) },
+-	{ IEEE80211_MODE_11A,			X(rcl11) },
+-#ifdef ATH_TURBO_SCAN
+-	{ IEEE80211_MODE_TURBO_G,		X(rcl12) },
+-#endif /* ATH_TURBO_SCAN */
+-	{ .list = NULL }
+-};
+-
+-#undef X
+-/* This function must be invoked with locks acquired */
+-static void
+-add_channels(struct ieee80211com *ic,
+-	struct ieee80211_scan_state *ss,
+-	enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq)
+-{
+-	struct ieee80211_channel *c, *cg;
+-	u_int modeflags;
+-	int i;
+-
+-	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
+-	modeflags = chanflags[mode];
+-	for (i = 0; i < nfreq; i++) {
+-		c = ieee80211_find_channel(ic, freq[i], modeflags);
+-		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
+-			continue;
+-		if (mode == IEEE80211_MODE_AUTO) {
+-			/* XXX special-case 11b/g channels so we select
+-			 *     the g channel if both are present. */
+-			if (IEEE80211_IS_CHAN_B(c) &&
+-			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
+-				c = cg;
+-		}
+-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-			break;
+-		ss->ss_chans[ss->ss_last++] = c;
+-	}
+-}
+-
+-/* This function must be invoked with locks acquired */
+-static int
+-checktable(const struct scanlist *scan, const struct ieee80211_channel *c)
+-{
+-	int i;
+-
+-	for (; scan->list != NULL; scan++) {
+-		for (i = 0; i < scan->count; i++)
+-			if (scan->list[i] == c->ic_freq)
+-				return 1;
+-	}
+-	return 0;
+-}
+ 
+ /*
+  * Attach prior to any scanning work.
+@@ -398,29 +274,6 @@
+ 		ieee80211_saveie(iep, ie);
+ }
+ 
+-/* This function must be invoked with locks acquired */
+-static struct ieee80211_channel *
+-find11gchannel(struct ieee80211com *ic, int i, int freq)
+-{
+-	struct ieee80211_channel *c;
+-	int j;
+-
+-	/* The normal ordering in the channel list is b channel
+-	 * immediately followed by g so optimize the search for
+-	 * this.  We'll still do a full search just in case. */
+-	for (j = i + 1; j < ic->ic_nchans; j++) {
+-		c = &ic->ic_channels[j];
+-		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
+-			return c;
+-	}
+-	for (j = 0; j < i; j++) {
+-		c = &ic->ic_channels[j];
+-		if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c))
+-			return c;
+-	}
+-	return NULL;
+-}
+-
+ /*
+  * Start an ap scan by populating the channel list.
+  */
+@@ -429,90 +282,14 @@
+ {
+ 	struct ap_state *as 	    = ss->ss_priv;
+ 	struct ieee80211com *ic     = NULL;
+-	const struct scanlist *sl   = NULL;
+-	struct ieee80211_channel *c = NULL;
+-	int i;
+-	unsigned int mode = 0;
+ 
+ 	SCAN_AP_LOCK_IRQ(as);
+ 	ic = vap->iv_ic;
+ 	/* Determine mode flags to match, or leave zero for auto mode */
+ 	as->as_vap_desired_mode = vap->iv_des_mode;
+ 	as->as_required_mode    = 0;
+-	if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) {
+-		as->as_required_mode = chanflags[as->as_vap_desired_mode];
+-		if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && 
+-		    (as->as_required_mode != IEEE80211_CHAN_ST)) {
+-			/* Fixup for dynamic turbo flags */
+-			if (as->as_vap_desired_mode == IEEE80211_MODE_11G)
+-				as->as_required_mode = IEEE80211_CHAN_108G;
+-			else
+-				as->as_required_mode = IEEE80211_CHAN_108A;
+-		}
+-	}
+-
+-	ss->ss_last = 0;
+-	/* Use the table of ordered channels to construct the list
+-	 * of channels for scanning.  Any channels in the ordered
+-	 * list not in the master list will be discarded. */
+-	for (sl = staScanTable; sl->list != NULL; sl++) {
+-		mode = sl->mode;
+-
+-		/* The scan table marks 2.4Ghz channels as b
+-		 * so if the desired mode is 11g, then use
+-		 * the 11b channel list but upgrade the mode. */
+-		if (as->as_vap_desired_mode &&
+-		    (as->as_vap_desired_mode != mode) && 
+-		    (as->as_vap_desired_mode == IEEE80211_MODE_11G) && 
+-		    (mode == IEEE80211_MODE_11B))
+-			mode = IEEE80211_MODE_11G;
+-
+-		/* If we are in "AUTO" mode, upgrade the mode to auto. 
+-		 * This lets add_channels upgrade an 11b channel to 
+-		 * 11g if available. */
+-		if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B))
+-			mode = IEEE80211_MODE_AUTO;
+-
+-		/* Add the list of the channels; any that are not
+-		 * in the master channel list will be discarded. */
+-		add_channels(ic, ss, mode, sl->list, sl->count);
+-	}
+-
+-	/* Add the channels from the ic (from HAL) that are not present
+-	 * in the staScanTable, assuming they pass the sanity checks... */
+-	for (i = 0; i < ic->ic_nchans; i++) {
+-		c = &ic->ic_channels[i];
+-
+-		/* XR is not supported on turbo channels */
+-		if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR)
+-			continue;
++	ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
+ 
+-		/* Dynamic channels are scanned in base mode */
+-		if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c))
+-			continue;
+-
+-		/* Use any 11g channel instead of 11b one. */
+-		if (vap->iv_des_mode == IEEE80211_MODE_AUTO && 
+-		    IEEE80211_IS_CHAN_B(c) &&
+-		    find11gchannel(ic, i, c->ic_freq))
+-			continue;
+-
+-		/* Do not add channels already put into the scan list by the
+-		 * scan table - these have already been filtered by mode
+-		 * and for whether they are in the active channel list. */
+-		if (checktable(staScanTable, c))
+-			continue;
+-
+-		/* Make sure the channel is active */
+-		if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee))
+-			continue;
+-
+-		/* Don't overrun */
+-		if (ss->ss_last >= IEEE80211_SCAN_MAX)
+-			break;
+-
+-		ss->ss_chans[ss->ss_last++] = c;
+-	}
+ 	ss->ss_next = 0;
+ 	/* XXX tunables */
+ 	ss->ss_mindwell = msecs_to_jiffies(200);	/* 200ms */
+@@ -831,13 +608,6 @@
+ 		if (IEEE80211_IS_CHAN_RADAR(c->chan))
+ 			continue;
+ 
+-		/* Do not select 802.11a ST if mode is specified and is not 
+-		 * 802.11a ST */
+-		if (as->as_required_mode &&
+-		    IEEE80211_IS_CHAN_STURBO(c->chan) &&
+-		    (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A))
+-			continue;
+-
+ 		/* Verify mode matches any fixed mode specified */
+ 		if ((c->chan->ic_flags & as->as_required_mode) != 
+ 				as->as_required_mode)
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -969,6 +969,80 @@
+ 	}
+ }
+ 
++static const u_int chanflags[] = {
++	0,	/* IEEE80211_MODE_AUTO */
++	IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
++	IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
++	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
++	IEEE80211_CHAN_FHSS,	/* IEEE80211_MODE_FH */
++	IEEE80211_CHAN_A,	/* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */
++	IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_TURBO_G */
++	IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_STATIC_A */
++};
++
++static struct ieee80211_channel *
++find11gchannel(struct ieee80211com *ic, int i, int freq)
++{
++	struct ieee80211_channel *c;
++	int j;
++
++	/*
++	 * The normal ordering in the channel list is b channel
++	 * immediately followed by g so optimize the search for
++	 * this.  We'll still do a full search just in case.
++	 */
++	for (j = i+1; j < ic->ic_nchans; j++) {
++		c = &ic->ic_channels[j];
++		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
++			return c;
++	}
++	for (j = 0; j < i; j++) {
++		c = &ic->ic_channels[j];
++		if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
++			return c;
++	}
++	return NULL;
++}
++
++
++void
++ieee80211_scan_add_channels(struct ieee80211com *ic,
++	struct ieee80211_scan_state *ss,
++	enum ieee80211_phymode mode)
++{
++	struct ieee80211_channel *c, *cg;
++	u_int modeflags;
++	int i;
++
++	KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode));
++	modeflags = chanflags[mode];
++	for (i = 0; i < ic->ic_nchans; i++) {
++		c = &ic->ic_channels[i];
++		if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee))
++			continue;
++		if (c->ic_scanflags & IEEE80211_NOSCAN_SET)
++			continue;
++		if (modeflags &&
++			((c->ic_flags & IEEE80211_CHAN_ALLTURBO) !=
++			 (modeflags & IEEE80211_CHAN_ALLTURBO)))
++			continue;
++		if (mode == IEEE80211_MODE_AUTO) {
++			/*
++			 * XXX special-case 11b/g channels so we select
++			 *     the g channel if both are present.
++			 */
++			if (IEEE80211_IS_CHAN_B(c) &&
++			    (cg = find11gchannel(ic, i, c->ic_freq)) != NULL)
++				continue;
++		}
++		if (ss->ss_last >= IEEE80211_SCAN_MAX)
++			break;
++		ss->ss_chans[ss->ss_last++] = c;
++	}
++}
++EXPORT_SYMBOL(ieee80211_scan_add_channels);
++
++
+ /*
+  * Execute radar channel change. This is called when a radar/dfs
+  * signal is detected.  AP mode only.  Return 1 on success, 0 on
+--- a/net80211/ieee80211_scan.h
++++ b/net80211/ieee80211_scan.h
+@@ -219,4 +219,7 @@
+ void ieee80211_scanner_unregister(enum ieee80211_opmode,
+ 	const struct ieee80211_scanner *);
+ void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *);
++void ieee80211_scan_add_channels(struct ieee80211com *ic,
++	struct ieee80211_scan_state *ss,
++	enum ieee80211_phymode mode);
+ #endif /* _NET80211_IEEE80211_SCAN_H_ */
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -3911,6 +3911,106 @@
+ 	return ieee80211_ioctl_setmlme(dev, info, w, (char *)&mlme);
+ }
+ 
++static inline void setflag(struct ieee80211_channel *c, int flag)
++{
++	if (flag)
++		c->ic_scanflags |= IEEE80211_NOSCAN_SET;
++	else
++		c->ic_scanflags &= ~IEEE80211_NOSCAN_SET;
++}
++
++static void setscanflag(struct ieee80211com *ic, int min, int max, int set)
++{
++	int i;
++
++	for (i = 0; i < ic->ic_nchans; i++) {
++		struct ieee80211_channel *c = &ic->ic_channels[i];
++
++		if (min == -1) {
++			if (!(c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT))
++				setflag(c, set);
++		} else if ((c->ic_freq >= min) && (c->ic_freq <= max)) {
++			setflag(c, set);
++		}
++	}
++}
++
++static int
++ieee80211_ioctl_setscanlist(struct net_device *dev,
++	struct iw_request_info *info,
++	struct iw_point *data, char *extra)
++{
++	struct ieee80211vap *vap = dev->priv;
++	struct ieee80211com *ic = vap->iv_ic;
++	char *s, *next;
++	int val = 1;
++
++	if (data->length <= 0)
++		return -EINVAL;
++
++	s = kmalloc(data->length + 1, GFP_KERNEL);
++	if (!s)
++		return -ENOMEM;
++
++	memset(s, 0, data->length + 1);
++	if (copy_from_user(s, data->pointer, data->length))
++		return -EFAULT;
++
++	s[data->length - 1] = '\0';		/* ensure null termination */
++
++	switch(*s) {
++		case '-':
++			val = 1;
++			break;
++		case '+':
++			val = 0;
++			break;
++		default:
++			goto error;
++	}
++	s++;
++	next = s;
++	do {
++		next = strchr(s, ',');
++		if (next) {
++			*next = 0;
++			next++;
++		}
++		if (!strcmp(s, "ALL")) {
++			setscanflag(ic, 0, 10000, val);
++		} else if (!strcmp(s, "REG")) {
++			setscanflag(ic, -1, -1, val);
++		} else {
++			int min, max;
++			char *n, *end = NULL;
++
++			n = strchr(s, '-');
++			if (n) {
++				*n = 0;
++				n++;
++			}
++			min = simple_strtoul(s, &end, 10);
++			if (end && *end)
++				goto error;
++			if (n) {
++				max = simple_strtoul(n, &end, 10);
++				if (end && *end)
++					goto error;
++			} else {
++				max = min;
++			}
++			setscanflag(ic, min, max, val);
++		}
++		s = next;
++	} while (next);
++	return 0;
++
++error:
++	if (s)
++		kfree(s);
++	return -EINVAL;
++}
++
+ static int
+ ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info,
+ 	void *w, char *extra)
+@@ -5712,6 +5812,8 @@
+ 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"},
+ 	{IEEE80211_PARAM_MINRATE,
+ 	 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
++	{ IEEE80211_IOCTL_SETSCANLIST,
++	 IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
+ 	
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	/*
+@@ -5809,6 +5911,7 @@
+ 	set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
+ 	set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
+ 	set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
++	set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
+ #ifdef ATH_REVERSE_ENGINEERING
+ 	set_priv(IEEE80211_IOCTL_READREG, ieee80211_ioctl_readreg),
+ 	set_priv(IEEE80211_IOCTL_WRITEREG, ieee80211_ioctl_writereg),
diff --git a/package/madwifi/patches-testing/316-ani_fix.patch b/package/madwifi/patches-testing/316-ani_fix.patch
new file mode 100644
index 000000000..ad7deb036
--- /dev/null
+++ b/package/madwifi/patches-testing/316-ani_fix.patch
@@ -0,0 +1,730 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -343,6 +343,8 @@
+ 		unsigned int param, unsigned int value);
+ 
+ static u_int32_t ath_get_real_maxtxpower(struct ath_softc *sc);
++static int ath_setintmit(struct ath_softc *sc);
++static u_int32_t ath_calcrxfilter(struct ath_softc *sc);
+ 
+ #ifdef AR_DEBUG
+ static int ath_txq_check(struct ath_softc *sc, struct ath_txq *txq, const char *msg);
+@@ -356,7 +358,6 @@
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+ static int hal_tpc = 0;
+-static int intmit = 0;
+ static int countrycode = CTRY_DEFAULT;
+ static int maxvaps = ATH_MAXVAPS_DEFAULT;
+ static int outdoor = 0;
+@@ -398,7 +399,6 @@
+ #endif
+ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+-MODULE_PARM(intmit, "i");
+ #else
+ #include <linux/moduleparam.h>
+ module_param(beacon_cal, int, 0600);
+@@ -412,7 +412,6 @@
+ #endif
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+-module_param(intmit, int, 0600);
+ #endif
+ MODULE_PARM_DESC(countrycode, "Override default country code.  Default is 0.");
+ MODULE_PARM_DESC(maxvaps, "Maximum VAPs.  Default is 4.");
+@@ -428,7 +427,6 @@
+ 		"'none' to disable");
+ MODULE_PARM_DESC(ratectl, "Rate control algorithm [amrr|minstrel|onoe|sample], "
+ 		"defaults to '" DEF_RATE_CTL "'");
+-MODULE_PARM_DESC(intmit, "Enable interference mitigation by default.  Default is 0.");
+ 
+ #ifdef AR_DEBUG
+ static int	ath_debug = 0;
+@@ -585,23 +583,13 @@
+ 	if (ath_hal_hastxpowlimit(ah)) {
+ 		ic->ic_caps |= IEEE80211_C_TXPMGT;
+ 	}
+-	/* Interference mitigation/ambient noise immunity (ANI).
+-	 * In modes other than HAL_M_STA, it causes receive sensitivity
+-	 * problems for OFDM. */
++	/* Interference mitigation/ambient noise immunity (ANI). */
+ 	sc->sc_hasintmit = ath_hal_hasintmit(ah);
+-	sc->sc_useintmit = (intmit && sc->sc_hasintmit);
+-	if (!sc->sc_hasintmit && intmit) {
+-		WPRINTF(sc, "Interference mitigation was requested, but is not"
+-				"supported by the HAL/hardware.\n");
+-		intmit = 0; /* Stop use in future ath_attach(). */
+-	}
+-	else {
+-		ath_hal_setintmit(ah, sc->sc_useintmit);
+-		DPRINTF(sc, ATH_DEBUG_ANY, "Interference mitigation is "
+-			"supported.  Currently %s.\n",
+-			(sc->sc_useintmit ? "enabled" : "disabled"));
+-	}
+ 
++	/* auto, mode dependent */
++	sc->sc_useintmit = -1;
++	sc->sc_noise_immunity = -1;
++	sc->sc_ofdm_weak_det = -1;
+ 	sc->sc_dmasize_stomp = 0;
+ 
+ 	/*
+@@ -614,15 +602,6 @@
+ 	sc->sc_mrretry = ath_hal_setupxtxdesc(ah, NULL, 0,0, 0,0, 0,0);
+ 
+ 	/*
+-	 * Check if the device has hardware counters for PHY
+-	 * errors.  If so we need to enable the MIB interrupt
+-	 * so we can act on stat triggers.
+-	 */
+-	sc->sc_needmib = ath_hal_hwphycounters(ah) && 
+-		sc->sc_hasintmit && 
+-		sc->sc_useintmit;
+-
+-	/*
+ 	 * Get the hardware key cache size.
+ 	 */
+ 	sc->sc_keymax = ath_hal_keycachesize(ah);
+@@ -1593,37 +1572,6 @@
+ 	ath_init(dev);
+ }
+ 
+-/* NB: Int. mit. was not implemented so that it could be enabled/disabled,
+- * and actually in 0.9.30.13 HAL it really can't even be disabled because
+- * it will start adjusting registers even when we turn off the capability
+- * in the HAL.
+- *
+- * NB: This helper function basically clobbers all the related registers
+- * if we have disabled int. mit. cap, allowing us to turn it on and off and
+- * work around the bug preventing it from being disabled. */
+-static inline void ath_override_intmit_if_disabled(struct ath_softc *sc) {
+-	/* Restore int. mit. registers if they were turned off. */
+-	if (sc->sc_hasintmit && !sc->sc_useintmit)
+-		ath_hal_restore_default_intmit(sc->sc_ah);
+-	/* Sanity check... remove later. */
+-	if (!sc->sc_useintmit) {
+-		ath_hal_verify_default_intmit(sc->sc_ah);
+-		/* If we don't have int. mit. and we don't have DFS on channel,
+-		 * it is safe to filter error packets. */
+-		if (!ath_radar_is_dfs_required(sc, &sc->sc_curchan)) {
+-			ath_hal_setrxfilter(sc->sc_ah,
+-				ath_hal_getrxfilter(sc->sc_ah) & 
+-				~HAL_RX_FILTER_PHYERR);
+-		}
+-	}
+-	else {
+-		/* Make sure that we have errors in RX filter because ANI needs
+-		 * them. */
+-		ath_hal_setrxfilter(sc->sc_ah, 
+-			ath_hal_getrxfilter(sc->sc_ah) | HAL_RX_FILTER_PHYERR);
+-	}
+-}
+-
+ static HAL_BOOL ath_hw_reset(struct ath_softc *sc, HAL_OPMODE opmode,
+ 		HAL_CHANNEL *channel, HAL_BOOL bChannelChange,
+ 		HAL_STATUS *status)
+@@ -1698,11 +1646,7 @@
+ 		ath_hal_settpc(sc->sc_ah, hal_tpc);
+ 	}
+ #endif
+-#if 0 /* Setting via HAL does not work, so it is done manually below. */
+-	if (sc->sc_hasintmit)
+-		ath_hal_setintmit(sc->sc_ah, sc->sc_useintmit);
+-#endif
+-	ath_override_intmit_if_disabled(sc);
++	ath_setintmit(sc);
+ 	if (sc->sc_dmasize_stomp)
+ 		ath_hal_set_dmasize_pcie(sc->sc_ah);
+ 	if (sc->sc_softled)
+@@ -2496,7 +2440,6 @@
+ 
+ 			/* Let the HAL handle the event. */
+ 			ath_hal_mibevent(ah, &sc->sc_halstats);
+-			ath_override_intmit_if_disabled(sc);
+ 		}
+ 	}
+ 	if (needmark)
+@@ -2564,6 +2507,55 @@
+ 	return flags;
+ }
+ 
++static int ath_setintmit(struct ath_softc *sc)
++{
++	struct ath_hal *ah = sc->sc_ah;
++	int ret;
++	int val;
++
++	if (!sc->sc_hasintmit)
++		return 0;
++
++	switch(sc->sc_useintmit) {
++		case 0: /* disabled */
++		case 1: /* enabled */
++			val = sc->sc_useintmit;
++			break;
++		default:
++			if (sc->sc_opmode != IEEE80211_M_MONITOR)
++				val = 1;
++			else
++				val = 0;
++			break;
++	}
++	ret = ath_hal_setintmit(ah, val);
++	if (val)
++		goto done;
++
++	/* manual settings */
++	if ((sc->sc_noise_immunity >= 0) && (sc->sc_noise_immunity <= 5))
++		ath_hal_setcapability(ah, HAL_CAP_INTMIT, 2, sc->sc_noise_immunity, NULL);
++	if ((sc->sc_ofdm_weak_det == 0) || (sc->sc_ofdm_weak_det == 1))
++		ath_hal_setcapability(ah, HAL_CAP_INTMIT, 3, sc->sc_ofdm_weak_det, NULL);
++
++done:
++	if (!sc->sc_imask)
++		goto out;
++
++	/* MIB interrupt handling */
++	sc->sc_needmib = ath_hal_hwphycounters(ah) &&
++		sc->sc_useintmit;
++	if (sc->sc_needmib)
++		sc->sc_imask |= HAL_INT_MIB;
++	else
++		sc->sc_imask &= ~HAL_INT_MIB;
++	ath_hal_intrset(sc->sc_ah, sc->sc_imask);
++	ath_calcrxfilter(sc);
++
++out:
++	return ret;
++}
++
+ /*
+  * Context: process context
+  */
+@@ -4249,8 +4241,7 @@
+ 	u_int32_t rfilt;
+ 
+ 	/* Preserve the current Phy. radar and err. filters. */
+-	rfilt = (ath_hal_getrxfilter(ah) &
+-			(HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)) |
++	rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYRADAR) |
+ 		 HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST |
+ 		 HAL_RX_FILTER_MCAST;
+ 	if (ic->ic_opmode != IEEE80211_M_STA)
+@@ -4266,6 +4257,8 @@
+ 	if (sc->sc_nmonvaps > 0)
+ 		rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
+ 			  HAL_RX_FILTER_PROBEREQ | HAL_RX_FILTER_PROM);
++	if (sc->sc_hasintmit && !sc->sc_needmib && ath_hal_getintmit(ah, NULL))
++		rfilt |= HAL_RX_FILTER_PHYERR;
+ 	if (sc->sc_curchan.privFlags & CHANNEL_DFS)
+ 		rfilt |= (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR);
+ 	return rfilt;
+@@ -6810,8 +6803,7 @@
+ 	dev->quota -= bf_processed;
+ #endif
+ 
+-	if (sc->sc_useintmit) 
+-		ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
++	ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan);
+ 	if (!bf_processed)
+ 		DPRINTF(sc, ATH_DEBUG_RX_PROC,
+ 			"Warning: %s got scheduled when no receive "
+@@ -8727,7 +8719,6 @@
+ 	ath_hal_rxena(ah);		/* enable recv descriptors */
+ 	ath_mode_init(dev);		/* set filters, etc. */
+ 	ath_hal_startpcurecv(ah);	/* re-enable PCU/DMA engine */
+-	ath_override_intmit_if_disabled(sc);
+ 	return 0;
+ }
+ 
+@@ -10633,8 +10624,10 @@
+ 	ATH_RP_IGNORED 		= 24,
+ 	ATH_RADAR_IGNORED       = 25,
+ 	ATH_MAXVAPS  		= 26,
+-        ATH_INTMIT 		= 27,
+-	ATH_DISTANCE		= 28,
++	ATH_DISTANCE		= 27,
++	ATH_INTMIT			= 28,
++	ATH_NOISE_IMMUNITY	= 29,
++	ATH_OFDM_WEAK_DET	= 30
+ };
+ 
+ static inline int 
+@@ -10696,6 +10689,48 @@
+ }
+ 
+ static int
++ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val)
++{
++	int ret;
++
++	switch(ctl) {
++	case ATH_INTMIT:
++		sc->sc_intmit = val;
++		break;
++	case ATH_NOISE_IMMUNITY:
++		sc->sc_noise_immunity = val;
++		break;
++	case ATH_OFDM_WEAK_DET:
++		sc->sc_ofdm_weak_det = val;
++		break;
++	default:
++		return -EINVAL;
++	}
++	ret = ath_setintmit(sc);
++	return ret;
++}
++
++static int
++ath_sysctl_get_intmit(struct ath_softc *sc, long ctl, u_int *val)
++{
++	struct ath_hal *ah = sc->sc_ah;
++
++	switch(ctl) {
++	case ATH_INTMIT:
++		*val = (ath_hal_getcapability(ah, HAL_CAP_INTMIT, 1, NULL) == HAL_OK);
++		break;
++	case ATH_NOISE_IMMUNITY:
++		return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 2, val);
++	case ATH_OFDM_WEAK_DET:
++		return ath_hal_getcapability(ah, HAL_CAP_INTMIT, 3, val);
++	default:
++		return -EINVAL;
++	}
++	return 0;
++}
++
++
++static int
+ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
+ {
+ 	struct ath_softc *sc = ctl->extra1;
+@@ -10934,30 +10969,13 @@
+ 				sc->sc_radar_ignored = val;
+ 				break;
+ 			case ATH_INTMIT:
+-				if (!sc->sc_hasintmit) {
++			case ATH_NOISE_IMMUNITY:
++			case ATH_OFDM_WEAK_DET:
++				if (!sc->sc_hasintmit)
+ 					ret = -EOPNOTSUPP;
+-					break;
+-				}
+-				if (sc->sc_useintmit == val)
+-					break;
+-				sc->sc_useintmit = val; 
+-				sc->sc_needmib = ath_hal_hwphycounters(ah) && 
+-					sc->sc_useintmit;
+-				/* Update the HAL and MIB interrupt mask bits */
+-				ath_hal_setintmit(ah, !!val); 
+-				sc->sc_imask = (sc->sc_imask & ~HAL_INT_MIB) | 
+-					(sc->sc_needmib ? HAL_INT_MIB : 0);
+-				ath_hal_intrset(sc->sc_ah, sc->sc_imask);
+-				/* Only do a reset if device is valid and UP 
+-				 * and we just made a change to the settings. */
+-				if (sc->sc_dev && !sc->sc_invalid &&
+-				    (sc->sc_dev->flags & IFF_RUNNING))
+-					ath_reset(sc->sc_dev); 
+-				/* NB: Run this step to cleanup if HAL doesn't 
+-				 * obey capability flags and hangs onto ANI
+-				 * settings. */
+-				ath_override_intmit_if_disabled(sc);
+-                                break; 
++				else
++					ret = ath_sysctl_set_intmit(sc, (long)ctl->extra2, val);
++				break;
+ 			default:
+ 				ret = -EINVAL;
+ 				break;
+@@ -11029,9 +11047,14 @@
+ 		case ATH_RADAR_IGNORED:
+ 			val = sc->sc_radar_ignored;
+ 			break;
+-                case ATH_INTMIT: 
+-			val = sc->sc_useintmit; 
+-			break; 
++		case ATH_INTMIT:
++		case ATH_NOISE_IMMUNITY:
++		case ATH_OFDM_WEAK_DET:
++			if (!sc->sc_hasintmit)
++				ret = -EOPNOTSUPP;
++			else
++				ret = ath_sysctl_get_intmit(sc, (long)ctl->extra2, &val);
++			break;
+ 		default:
+ 			ret = -EINVAL;
+ 			break;
+@@ -11413,6 +11436,24 @@
+ 	  .maxlen	= sizeof(ath_xchanmode),
+ 	  .proc_handler	= proc_dointvec
+ 	},
++	{ .ctl_name	= CTL_AUTO,
++	  .procname     = "intmit",
++	  .mode         = 0644,
++	  .proc_handler = ath_sysctl_halparam,
++	  .extra2	= (void *)ATH_INTMIT,
++	},
++	{ .ctl_name	= CTL_AUTO,
++	  .procname     = "noise_immunity",
++	  .mode         = 0644,
++	  .proc_handler = ath_sysctl_halparam,
++	  .extra2	= (void *)ATH_NOISE_IMMUNITY,
++	},
++	{ .ctl_name	= CTL_AUTO,
++	  .procname     = "ofdm_weak_det",
++	  .mode         = 0644,
++	  .proc_handler = ath_sysctl_halparam,
++	  .extra2	= (void *)ATH_OFDM_WEAK_DET,
++	},
+ 	{ 0 }
+ };
+ static ctl_table ath_ath_table[] = {
+--- a/ath/if_athvar.h
++++ b/ath/if_athvar.h
+@@ -712,6 +712,10 @@
+ 	unsigned int sc_txcont_power; /* Continuous transmit power in 0.5dBm units */
+ 	unsigned int sc_txcont_rate;  /* Continuous transmit rate in Mbps */
+ 
++	int8_t sc_intmit; /* Interference mitigation enabled, -1 = auto, based on mode, 0/1 = off/on */
++	int8_t sc_noise_immunity; /* Noise immunity level, 0-4, -1 == auto) */
++	int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */
++
+ 	/* rate tables */
+ 	const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
+ 	const HAL_RATE_TABLE *sc_currates;	/* current rate table */
+--- a/ath/if_ath_hal_extensions.h
++++ b/ath/if_ath_hal_extensions.h
+@@ -237,296 +237,18 @@
+ 	AR5K_DMASIZE_512B
+ };
+ 
+-
+-int ath_set_ack_bitrate(struct ath_softc *sc, int);
+-int ar_device(int devid);
+-const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
+-
+-static inline unsigned long field_width(unsigned long mask, unsigned long shift)
+-{
+-	unsigned long r = 0;
+-	unsigned long x = mask >> shift;
+-	if ( 0 == mask )  return  0;
+-#if  BITS_PER_LONG >= 64
+-	if ( x & (~0UL<<32) )  { x >>= 32;  r += 32; }
+-#endif
+-	if ( x & 0xffff0000 )  { x >>= 16;  r += 16; }
+-	if ( x & 0x0000ff00 )  { x >>=  8;  r +=  8; }
+-	if ( x & 0x000000f0 )  { x >>=  4;  r +=  4; }
+-	if ( x & 0x0000000c )  { x >>=  2;  r +=  2; }
+-	if ( x & 0x00000002 )  {            r +=  1; }
+-	return r+1;
+-}
+-
+-static inline u_int32_t get_field(struct ath_hal *ah, u_int32_t reg, u_int32_t mask, u_int32_t shift, int is_signed) {
+-	unsigned long x = ((OS_REG_READ(ah, reg) & mask) >> shift);
+-	if (is_signed) {
+-		unsigned long c =(-1) << (field_width(mask, shift)-1);
+-		return (x + c) ^ c;
+-	}
+-	return x;
+-}
+-
+ static inline void set_field(struct ath_hal *ah, u_int32_t reg, u_int32_t mask, u_int32_t shift, u_int32_t value) {
+ 	OS_REG_WRITE(ah, reg, 
+ 			  (OS_REG_READ(ah, reg) & ~mask) | 
+ 			  ((value << shift) & mask));
+ }
+ 
+-static inline u_int32_t field_eq(struct ath_hal *ah, u_int32_t reg, 
+-				 u_int32_t mask, u_int32_t shift, 
+-				 u_int32_t value, int is_signed) {
+-	return  (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)) == 
+-		(value & (mask >> shift));
+-}
+-
+-static inline void override_warning(struct ath_hal *ah, const char *name,
+-				    u_int32_t reg, u_int32_t mask,
+-				    u_int32_t shift, u_int32_t expected, int is_signed) {
+-
+-	if (!field_eq(ah, reg, mask, shift, expected, is_signed)) 
+-		printk("%s: Correcting 0x%04x[%s] from 0x%x (%d) to 0x%x (%d).\n", 
+-		       SC_DEV_NAME(ah->ah_sc),
+-		       reg,
+-		       name, 
+-		       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)),
+-		       get_field(ah, reg, mask, shift, is_signed), 
+-		       (expected & (mask >> shift)), /* not sign extended */
+-		       expected);
+-#if 0 /* NB: For checking to see if HAL is fixed or not */
+-	else {
+-			printk("%s: Keeping 0x%04x[%s] - 0x%x (%d).\n",
+-			       SC_DEV_NAME(ah->ah_sc),
+-			       reg,
+-			       name, 
+-			       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)),
+-			       get_field(ah, reg, mask, shift, is_signed));
+-	}
+-#endif
+-}
+-
+-static inline void verification_warning(struct ath_hal *ah, const char *name,
+-    u_int32_t reg, u_int32_t mask, 
+-    u_int32_t shift, u_int32_t expected, int is_signed) {
+-
+-	int ret = field_eq(ah, reg, mask, shift, expected, is_signed);
+-	if (!ret) {
+-		printk("%s: %s verification of %s default value "
+-		       "[found=0x%x (%d) expected=0x%x (%d)].\n", 
+-		       SC_DEV_NAME(ah->ah_sc),
+-		       (ret ? "PASSED" : "FAILED"),
+-			name, 
+-		       (get_field(ah, reg, mask, shift, is_signed) & (mask >> shift)), 
+-		       get_field(ah, reg, mask, shift, is_signed), 
+-		       (expected & (mask >> shift)), /* not sign extended */
+-		       expected);
+-		ath_hal_print_decoded_register(ah, NULL, reg, 
+-					       OS_REG_READ(ah, reg), OS_REG_READ(ah, reg), 0);
+-	}
+-}
+-
+-#define GET_FIELD(ah, __reg, __mask, __signed) \
+-	get_field(ah, __reg, __mask, __mask ## _S, __signed)
+ #define SET_FIELD(ah, __reg, __mask, __value) \
+ 	set_field(ah, __reg, __mask, __mask ## _S, __value);
+-#define FIELD_EQ(ah, __reg, __mask, __value, __signed) \
+-	field_eq(ah, __reg, __mask, __mask ## _S, __value, __signed)
+-
+-#if 0 /* NB: These are working at this point, and HAL tweaks them a lot */
+-#define OVERRIDE_WARNING(ah, __reg, __mask, __expected, __signed) \
+-	override_warning(ah, #__mask, __reg, __mask, __mask ## _S, __expected, __signed)
+-#else
+-#define OVERRIDE_WARNING(ah, __reg, __mask, __expected, __signed) 
+-#endif
+-	
+-#define VERIFICATION_WARNING(ah, __reg, __mask, __signed) \
+-	verification_warning(ah, #__mask, __reg, __mask, __mask ## _S, DEFAULT_ ## __mask, __signed)
+-#define VERIFICATION_WARNING_SW(ah, __reg, __mask, __signed) \
+-	verification_warning(ah, #__mask, __reg, __mask, __mask ## _S, DEFAULT_ENABLE_ ## __reg ? __mask ## _ON : __mask ## _OFF, __signed)
+-
+-static inline void ath_hal_set_noise_immunity(struct ath_hal *ah,
+-					      int agc_desired_size, 
+-					      int agc_coarse_hi,
+-					      int agc_coarse_lo, 
+-					      int sig_firpwr) 
+-{
+-	ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-	ath_hal_set_function(__func__);
+-	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+-
+-#if 0 /* NB: These are working at this point, and HAL tweaks them a lot */
+-	OVERRIDE_WARNING(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, agc_desired_size, 1);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, agc_coarse_lo, 1);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, agc_coarse_hi, 1);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, sig_firpwr, 1);
+-#endif
+-
+-	SET_FIELD(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, agc_desired_size);
+-	SET_FIELD(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, agc_coarse_lo);
+-	SET_FIELD(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, agc_coarse_hi);
+-	SET_FIELD(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, sig_firpwr);
+-
+-	ath_hal_set_function(NULL);
+-	ath_hal_set_device(NULL);
+-	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-}
+-
+-static inline void ath_hal_set_ofdm_weak_det(struct ath_hal *ah, 
+-	int low_m1, int low_m2, int low_m2_count, int low_self_corr,
+-	int high_m1, int high_m2, int high_m2_count)
+-{
+-	ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-	ath_hal_set_function(__func__);
+-	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+-
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, low_m1, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, low_m2, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, low_m2_count, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, low_self_corr, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, high_m1, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, high_m2, 0);
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, high_m2_count, 0);
+-
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, low_m1);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, low_m2);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, low_m2_count);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, low_self_corr);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, high_m1);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, high_m2);
+-	SET_FIELD(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, high_m2_count);
+-
+-	ath_hal_set_function(NULL);
+-	ath_hal_set_device(NULL);
+-	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-}
+-
+-static inline void ath_hal_set_cck_weak_det(struct ath_hal *ah, int thresh)
+-{
+-	ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-	ath_hal_set_function(__func__);
+-	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+-
+-	OVERRIDE_WARNING(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, thresh, 0);
+-
+-	SET_FIELD(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, thresh);
+-
+-	ath_hal_set_function(NULL);
+-	ath_hal_set_device(NULL);
+-	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-}
+-
+-static inline void ath_hal_set_sig_firstep(struct ath_hal *ah, int firstep)
+-{
+-	ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-	ath_hal_set_function(__func__);
+-	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+ 
+-	OVERRIDE_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, firstep, 0);
+-
+-	SET_FIELD(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, firstep);
+-
+-	ath_hal_set_function(NULL);
+-	ath_hal_set_device(NULL);
+-	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-}
+-
+-static inline void ath_hal_set_spur_immunity(struct ath_hal *ah, int thresh)
+-{
+-	ATH_HAL_LOCK_IRQ(ah->ah_sc);
+-	ath_hal_set_function(__func__);
+-	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+-
+-	OVERRIDE_WARNING(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, thresh, 0);
+-
+-	SET_FIELD(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, thresh);
+-
+-	ath_hal_set_function(NULL);
+-	ath_hal_set_device(NULL);
+-	ATH_HAL_UNLOCK_IRQ(ah->ah_sc);
+-}
+-
+-static inline void ath_hal_restore_default_noise_immunity(struct ath_hal *ah) {
+-
+-	ath_hal_set_noise_immunity(ah, 
+-		DEFAULT_AR5K_PHY_AGCSIZE_DESIRED, 
+-		DEFAULT_AR5K_PHY_AGCCOARSE_HI,
+-		DEFAULT_AR5K_PHY_AGCCOARSE_LO,
+-		DEFAULT_AR5K_PHY_SIG_FIRPWR);
+-}
+-
+-static inline void ath_hal_enable_ofdm_weak_det(struct ath_hal *ah, int enable) {
+-	if (enable)
+-		ath_hal_set_ofdm_weak_det(ah, 
+-			AR5K_PHY_WEAK_OFDM_LOW_M1_ON,
+-			AR5K_PHY_WEAK_OFDM_LOW_M2_ON,
+-			AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT_ON,
+-		        AR5K_PHY_WEAK_OFDM_LOW_SELFCOR_ON,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M1_ON,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M2_ON,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT_ON);
+-	else
+-		ath_hal_set_ofdm_weak_det(ah, 
+-			AR5K_PHY_WEAK_OFDM_LOW_M1_OFF,
+-			AR5K_PHY_WEAK_OFDM_LOW_M2_OFF,
+-			AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT_OFF,
+-			AR5K_PHY_WEAK_OFDM_LOW_SELFCOR_OFF,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M1_OFF,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M2_OFF,
+-			AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT_OFF);
+-}
+-
+-static inline void ath_hal_enable_cck_weak_det(struct ath_hal *ah, int enable) {
+-	ath_hal_set_cck_weak_det(ah, enable 
+-				 ? AR5K_PHY_WEAK_CCK_THRESH_ON 
+-				 : AR5K_PHY_WEAK_CCK_THRESH_OFF);
+-}
+-
+-static inline void ath_hal_restore_default_ofdm_weak_det(struct ath_hal *ah) {
+-	ath_hal_enable_ofdm_weak_det(ah, DEFAULT_ENABLE_AR5K_PHY_WEAK_OFDM);
+-}
+-
+-static inline void ath_hal_restore_default_cck_weak_det(struct ath_hal *ah) {
+-	ath_hal_enable_cck_weak_det(ah, DEFAULT_ENABLE_AR5K_PHY_WEAK_CCK);
+-}
+-
+-static inline void ath_hal_restore_default_sig_firstep(struct ath_hal *ah) {
+-
+-	ath_hal_set_sig_firstep(ah, 
+-		DEFAULT_AR5K_PHY_SIG_FIRSTEP);
+-}
+-
+-static inline void ath_hal_restore_default_spur_immunity(struct ath_hal *ah) {
+-
+-	ath_hal_set_spur_immunity(ah, 
+-		DEFAULT_AR5K_PHY_SPUR_THRESH);
+-}
+-
+-static inline void ath_hal_restore_default_intmit(struct ath_hal *ah) {
+-	ath_hal_restore_default_noise_immunity(ah);
+-	ath_hal_restore_default_ofdm_weak_det(ah);
+-	ath_hal_restore_default_cck_weak_det(ah);
+-	ath_hal_restore_default_sig_firstep(ah);
+-	ath_hal_restore_default_spur_immunity(ah);
+-
+-}
+-
+-static inline void ath_hal_verify_default_intmit(struct ath_hal *ah) {
+-	/* Just a list of all the fields above, for sanity checks... */
+-	VERIFICATION_WARNING(ah, AR5K_PHY_AGCSIZE, AR5K_PHY_AGCSIZE_DESIRED, 1);
+-	VERIFICATION_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, 1);
+-	VERIFICATION_WARNING(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, 1);
+-	VERIFICATION_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, 1);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M1, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_M2_COUNT, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_LOW, AR5K_PHY_WEAK_OFDM_LOW_SELFCOR, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M1, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_OFDM_HIGH, AR5K_PHY_WEAK_OFDM_HIGH_M2_COUNT, 0);
+-	VERIFICATION_WARNING_SW(ah, AR5K_PHY_WEAK_CCK, AR5K_PHY_WEAK_CCK_THRESH, 0);
+-	VERIFICATION_WARNING(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, 0);
+-	VERIFICATION_WARNING(ah, AR5K_PHY_SPUR, AR5K_PHY_SPUR_THRESH, 0);
+-}
++int ath_set_ack_bitrate(struct ath_softc *sc, int);
++int ar_device(int devid);
++const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
+ 
+ static inline void ath_hal_set_dmasize_pcie(struct ath_hal *ah) {
+ 	SET_FIELD(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+--- a/ath/if_ath_hal.h
++++ b/ath/if_ath_hal.h
+@@ -79,7 +79,7 @@
+ 	ath_hal_set_function(__func__);
+ 	ath_hal_set_device(SC_DEV_NAME(ah->ah_sc));
+ 	ret =
+-	    ah->ah_getDiagState(ah, request, args, argsize, *result,
++	    ah->ah_getDiagState(ah, request, args, argsize, result,
+ 				resultsize);
+ 	ath_hal_set_function(NULL);
+ 	ath_hal_set_device(NULL);
+--- a/scripts/if_ath_hal_generator.pl
++++ b/scripts/if_ath_hal_generator.pl
+@@ -145,7 +145,9 @@
+     "ah_waitForBeaconDone"        => "ath_hal_waitforbeacon",
+     "ah_writeAssocid"             => "ath_hal_setassocid",
+     "ah_clrMulticastFilterIndex"  => "ath_hal_clearmcastfilter",
+-    "ah_detectCardPresent"        => "ath_hal_detectcardpresent"
++    "ah_detectCardPresent"        => "ath_hal_detectcardpresent",
++    "ah_setSifsTime"              => "ath_hal_setsifstime",
++    "ah_getSifsTime"              => "ath_hal_getsifstime"
+ );
+ 
+ #
+@@ -254,7 +256,7 @@
+ 
+     foreach (@parameters) {
+         s/ \*/\* /;
+-        /^((?:(?:const|struct|\*)\s*)*)([^\s]+\*?)\s*([^\s]*)\s*/;
++        /^((?:(?:const|struct|\*)\s*)*)([^\s]+\**)\s*([^\s]*)\s*/;
+         my $type = "$1$2";
+         my $name = "$3";
+         if ( 0 == length($name) ) {
diff --git a/package/madwifi/patches-testing/317-devid.patch b/package/madwifi/patches-testing/317-devid.patch
new file mode 100644
index 000000000..281e348f8
--- /dev/null
+++ b/package/madwifi/patches-testing/317-devid.patch
@@ -0,0 +1,17 @@
+--- a/ath/if_ath_pci.c
++++ b/ath/if_ath_pci.c
+@@ -114,11 +114,13 @@
+ 	{ 0x168c, 0x0023, PCI_ANY_ID, PCI_ANY_ID },
+ 	{ 0x168c, 0x0024, PCI_ANY_ID, PCI_ANY_ID },
+ 	{ 0x168c, 0x9013, PCI_ANY_ID, PCI_ANY_ID }, /* sonicwall */
++	{ 0x168c, 0xff1a, PCI_ANY_ID, PCI_ANY_ID },
+ 	{ 0 }
+ };
+ 
+ static u16 ath_devidmap[][2] = {
+-	{ 0x9013, 0x0013 }
++	{ 0x9013, 0x0013 },
++	{ 0xff1a, 0x001a }
+ };
+ 
+ static int
diff --git a/package/madwifi/patches-testing/318-ifxmips_eeprom.patch b/package/madwifi/patches-testing/318-ifxmips_eeprom.patch
new file mode 100644
index 000000000..412ceadeb
--- /dev/null
+++ b/package/madwifi/patches-testing/318-ifxmips_eeprom.patch
@@ -0,0 +1,85 @@
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -917,9 +917,56 @@
+  * NB: see the comments in ah_osdep.h about byte-swapping register
+  *     reads and writes to understand what's going on below.
+  */
++
++#ifdef CONFIG_IFXMIPS
++extern int ifxmips_has_brn_block(void);
++static int ifxmips_emulate = 0;
++#define EEPROM_EMULATION 1
++#endif
++
++#ifdef EEPROM_EMULATION
++static int ath_hal_eeprom(struct ath_hal *ah, unsigned long addr, int val, int write)
++{
++	static int addrsel = 0;
++	static int rc = 0;
++
++	if (write) {
++		if(addr == 0x6000) {
++			addrsel = val * 2;
++			rc = 0;
++		}
++	} else {
++		switch(addr)
++		{
++		case 0x600c:
++			if(rc++ < 2)
++				val = 0x00000000;
++			else
++				val = 0x00000002;
++			break;
++		case 0x6004:
++			val = cpu_to_le16(__raw_readw((u16 *) KSEG1ADDR(0xb07f0400 + addrsel)));
++			/* this forces the regdomain to 0x00 (worldwide), as the original setting
++			 * causes issues with the HAL */
++			if (addrsel == 0x17e)
++				val = 0;
++			break;
++		}
++	}
++	return val;
++}
++#endif
++
+ void __ahdecl
+ ath_hal_reg_write(struct ath_hal *ah, u_int address, u_int32_t value)
+ {
++#ifdef EEPROM_EMULATION
++	if((address >= 0x6000) && (address <= 0x6010) && ifxmips_emulate) {
++		ath_hal_eeprom(ah, address, value, 1);
++		return;
++	}
++#endif
++
+ 	_trace_regop(ah, REGOP_WRITE, address, value);
+ 	_OS_REG_WRITE(ah, address, value);
+ }
+@@ -929,7 +976,14 @@
+ u_int32_t __ahdecl
+ ath_hal_reg_read(struct ath_hal *ah, u_int address)
+ {
+- 	u_int32_t val = _OS_REG_READ(ah, address);
++	u_int32_t val;
++
++#ifdef EEPROM_EMULATION
++	if((address >= 0x6000) && (address <= 0x6010) && ifxmips_emulate)
++		val = ath_hal_eeprom(ah, address, 0, 0);
++	else
++#endif
++		val = _OS_REG_READ(ah, address);
+ 	_trace_regop(ah, REGOP_READ, address, val);
+ 	return val;
+ }
+@@ -1123,6 +1177,9 @@
+ #ifdef MMIOTRACE
+ 	kmmio_logmsg = _kmmio_logmsg;
+ #endif
++#ifdef CONFIG_IFXMIPS
++	ifxmips_emulate = ifxmips_has_brn_block();
++#endif
+ 
+ 	sep = "";
+ 	for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
diff --git a/package/madwifi/patches-testing/319-eap_auth_disassoc.patch b/package/madwifi/patches-testing/319-eap_auth_disassoc.patch
new file mode 100644
index 000000000..a1d9b0ba4
--- /dev/null
+++ b/package/madwifi/patches-testing/319-eap_auth_disassoc.patch
@@ -0,0 +1,81 @@
+This patch causes STA mode interfaces to disassociate if transmission of assoc/auth
+critical packets failed.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -8273,6 +8273,18 @@
+ #endif
+ 				if (ts->ts_status & HAL_TXERR_XRETRY) {
+ 					sc->sc_stats.ast_tx_xretries++;
++					if (SKB_CB(bf->bf_skb)->auth_pkt && (ni->ni_vap->iv_opmode == IEEE80211_M_STA)) {
++						struct ieee80211com *ic = &sc->sc_ic;
++
++						/* if roaming is enabled, try reassociating, otherwise
++						 * disassociate and go back to the scan state */
++						IEEE80211_VAPS_LOCK_BH(ic);
++						if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
++							ni->ni_vap->iv_newstate(ni->ni_vap, IEEE80211_S_ASSOC, 1);
++						else
++							ni->ni_vap->iv_newstate(ni->ni_vap, IEEE80211_S_SCAN, 0);
++						IEEE80211_VAPS_UNLOCK_BH(ic);
++					}
+ 					if (ni->ni_flags & IEEE80211_NODE_UAPSD_TRIG) {
+ 						ni->ni_stats.ns_tx_eosplost++;
+ 						DPRINTF(sc, ATH_DEBUG_UAPSD,
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -158,6 +158,7 @@
+ 
+ 		SKB_NI(skb) = NULL;
+ 		SKB_CB(skb)->flags = 0;
++		SKB_CB(skb)->auth_pkt = 0;
+ 
+ 		skb_reserve(skb, sizeof(struct ieee80211_frame));
+ 		*frm = skb_put(skb, pktlen);
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -411,6 +411,7 @@
+ #define M_SKB_TRACKED	0x20
+ 	void		(*next_destructor)(struct sk_buff *skb);
+ #endif
++	u_int8_t auth_pkt;
+ };
+ 
+ struct __assert {
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -773,6 +773,8 @@
+ 	else
+ 		hdrsize = sizeof(struct ieee80211_frame);
+ 
++	SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
++
+ 	switch (vap->iv_opmode) {
+ 	case IEEE80211_M_IBSS:
+ 	case IEEE80211_M_AHDEMO:
+@@ -1617,6 +1619,7 @@
+ 	ie->param_len = frm - &ie->param_oui[0];
+ 	return frm;
+ }
++
+ #endif
+ /*
+  * Send a probe request frame with the specified ssid
+@@ -1881,6 +1884,7 @@
+ 				sizeof(u_int16_t)+IEEE80211_CHALLENGE_LEN : 0));
+ 		if (skb == NULL)
+ 			senderr(ENOMEM, is_tx_nobuf);
++		SKB_CB(skb)->auth_pkt = 1;
+ 
+ 		((__le16 *)frm)[0] =
+ 			(is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
+@@ -1955,6 +1959,7 @@
+ 			vap->app_ie[IEEE80211_APPIE_FRAME_ASSOC_REQ].length);
+ 		if (skb == NULL)
+ 			senderr(ENOMEM, is_tx_nobuf);
++		SKB_CB(skb)->auth_pkt = 1;
+ 
+ 		capinfo = 0;
+ 		if (vap->iv_opmode == IEEE80211_M_IBSS)
diff --git a/package/madwifi/patches-testing/320-hidden_ssid.patch b/package/madwifi/patches-testing/320-hidden_ssid.patch
new file mode 100644
index 000000000..92d0480d2
--- /dev/null
+++ b/package/madwifi/patches-testing/320-hidden_ssid.patch
@@ -0,0 +1,38 @@
+This patch fixes the detection of hidden SSIDs as transmitted
+by some cisco systems.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -209,6 +209,19 @@
+ 		ieee80211_saveie(iep, ie);
+ }
+ 
++
++static inline int is_empty_ssid(u_int8_t *ssid)
++{
++	if (!ssid)
++		return 1;
++	if (ssid[1] == 0)
++		return 1;
++	if ((ssid[1] == 1) && (ssid[2] == 0))
++		return 1;
++	return 0;
++}
++
++
+ /*
+  * Process a beacon or probe response frame; create an
+  * entry in the scan cache or update any previous entry.
+@@ -252,8 +265,8 @@
+ 	ise = &se->base;
+ 
+ 	/* XXX ap beaconing multiple ssid w/ same bssid */
+-	if (sp->ssid[1] != 0 &&
+-	    (ISPROBE(subtype) || ise->se_ssid[1] == 0))
++	if (!is_empty_ssid(sp->ssid) &&
++	    (ISPROBE(subtype) || is_empty_ssid(ise->se_ssid)))
+ 		memcpy(ise->se_ssid, sp->ssid, 2 + sp->ssid[1]);
+ 
+ 	memcpy(ise->se_rates, sp->rates, 
diff --git a/package/madwifi/patches-testing/321-bgscan_rssi_thresh.patch b/package/madwifi/patches-testing/321-bgscan_rssi_thresh.patch
new file mode 100644
index 000000000..7020305ea
--- /dev/null
+++ b/package/madwifi/patches-testing/321-bgscan_rssi_thresh.patch
@@ -0,0 +1,127 @@
+Add an optional background scanning threshold triggered by low rssi
+(useful for passing updated scan results to the supplicant ahead of
+time, before losing connectivity entirely)
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -655,6 +655,7 @@
+ 	IEEE80211_PARAM_MINRATE			= 84,	/* Minimum rate (by table index) */
+ 	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
+ 	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
++	IEEE80211_PARAM_BGSCAN_THRESH		= 87,	/* bg scan rssi threshold */
+ };
+ 
+ #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -92,6 +92,8 @@
+ #define	IEEE80211_BGSCAN_IDLE_MIN	100	/* min idle time (ms) */
+ #define	IEEE80211_BGSCAN_IDLE_DEFAULT	250	/* default idle time (ms) */
+ 
++#define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */
++
+ #define IEEE80211_COVERAGE_CLASS_MAX	31	/* max coverage class */
+ #define IEEE80211_REGCLASSIDS_MAX	10	/* max regclass id list */
+ 
+@@ -229,6 +231,9 @@
+ 	u_int8_t iv_nickname[IEEE80211_NWID_LEN];
+ 	u_int iv_bgscanidle;				/* bg scan idle threshold */
+ 	u_int iv_bgscanintvl;				/* bg scan min interval */
++	u_int iv_bgscanthr;					/* bg scan rssi threshold */
++	u_int iv_bgscantrintvl;				/* bg scan trigger interval */
++	unsigned long iv_bgscanthr_next;		/* last trigger for bgscan */
+ 	u_int iv_scanvalid;				/* scan cache valid threshold */
+ 	struct ieee80211_roam iv_roam;			/* sta-mode roaming state */
+ 
+@@ -612,6 +617,7 @@
+ #define IEEE80211_FEXT_SWBMISS		0x00000400	/* CONF: use software beacon timer */
+ #define IEEE80211_FEXT_DROPUNENC_EAPOL	0x00000800	/* CONF: drop unencrypted eapol frames */
+ #define IEEE80211_FEXT_APPIE_UPDATE	0x00001000	/* STATE: beacon APP IE updated */
++#define IEEE80211_FEXT_BGSCAN_THR	0x00002000	/* bgscan due to low rssi */
+ 
+ #define IEEE80211_COM_UAPSD_ENABLE(_ic)		((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD)
+ #define IEEE80211_COM_UAPSD_DISABLE(_ic)	((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2778,6 +2778,9 @@
+ 		else
+ 			retv = EINVAL;
+ 		break;
++	case IEEE80211_PARAM_BGSCAN_THRESH:
++		vap->iv_bgscanthr = value;
++		break;
+ 	case IEEE80211_PARAM_MCAST_RATE:
+ 		/* units are in KILObits per second */
+ 		if (value >= 256 && value <= 54000)
+@@ -3181,6 +3184,9 @@
+ 	case IEEE80211_PARAM_BGSCAN_INTERVAL:
+ 		param[0] = vap->iv_bgscanintvl / HZ;	/* seconds */
+ 		break;
++	case IEEE80211_PARAM_BGSCAN_THRESH:
++		param[0] = vap->iv_bgscanthr;	/* rssi */
++		break;
+ 	case IEEE80211_PARAM_MCAST_RATE:
+ 		param[0] = vap->iv_mcast_rate;	/* seconds */
+ 		break;
+@@ -5704,6 +5710,10 @@
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanintvl" },
+ 	{ IEEE80211_PARAM_BGSCAN_INTERVAL,
+ 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanintvl" },
++	{ IEEE80211_PARAM_BGSCAN_THRESH,
++	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanthr" },
++	{ IEEE80211_PARAM_BGSCAN_THRESH,
++	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanthr" },
+ 	{ IEEE80211_PARAM_MCAST_RATE,
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcast_rate" },
+ 	{ IEEE80211_PARAM_MCAST_RATE,
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -2984,8 +2984,10 @@
+ {
+ 	struct ieee80211com *ic = vap->iv_ic;
+ 
++	vap->iv_bgscantrintvl = (vap->iv_bgscantrintvl + 1) % 4;
+ 	return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) &&
+-		time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle));
++		(((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && !vap->iv_bgscantrintvl) ||
++			time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)));
+ }
+ 
+ static __inline int
+@@ -3229,6 +3231,23 @@
+ 			/* record tsf of last beacon */
+ 			memcpy(ni->ni_tstamp.data, scan.tstamp,
+ 				sizeof(ni->ni_tstamp));
++
++			/* When rssi is low, start doing bgscans more frequently to allow
++			 * the supplicant to make a better switching decision */
++			if ((rssi < vap->iv_bgscanthr) &&
++					(!vap->iv_bgscanthr_next ||
++						!time_before(jiffies, vap->iv_bgscanthr_next)) &&
++					!(ic->ic_flags & IEEE80211_F_SCAN)) {
++				int ret;
++
++				ic->ic_lastdata = 0;
++				ic->ic_lastscan = 0;
++				ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN_THR;
++				ret = ieee80211_bg_scan(vap);
++				if (ret)
++					vap->iv_bgscanthr_next = jiffies + msecs_to_jiffies(IEEE80211_BGSCAN_TRIGGER_INTVL * 1000);
++			}
++
+ 			if (ni->ni_intval != scan.bintval) {
+ 				IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
+ 						"beacon interval divergence: "
+--- a/net80211/ieee80211_scan.c
++++ b/net80211/ieee80211_scan.c
+@@ -793,7 +793,7 @@
+ 				ieee80211_sta_pwrsave(vap, 0);
+ 				if (ss->ss_next >= ss->ss_last) {
+ 					ieee80211_notify_scan_done(vap);
+-					ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
++					ic->ic_flags_ext &= ~(IEEE80211_FEXT_BGSCAN|IEEE80211_FEXT_BGSCAN_THR);
+ 				}
+ 			}
+ 			SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
diff --git a/package/madwifi/patches-testing/322-ignore_broken_bssid.patch b/package/madwifi/patches-testing/322-ignore_broken_bssid.patch
new file mode 100644
index 000000000..0bae461f6
--- /dev/null
+++ b/package/madwifi/patches-testing/322-ignore_broken_bssid.patch
@@ -0,0 +1,18 @@
+Some misconfigured APs broadcast NULL BSSIDs, which can confuse the STA
+Ignore those when scanning.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -242,6 +242,10 @@
+ 	struct ieee80211_scan_entry *ise;
+ 	int hash;
+ 
++	/* workaround for broken APs that broadcast NULL BSSIDs */
++	if (memcmp(wh->i_addr3, "\x00\x00\x00\x00\x00\x00", 6) == 0)
++		return 0;
++
+ 	hash = STA_HASH(macaddr);
+ 	SCAN_STA_LOCK_IRQ(st);
+ 	LIST_FOREACH(se, &st->st_hash[hash], se_hash)
diff --git a/package/madwifi/patches-testing/323-crash_fix.patch b/package/madwifi/patches-testing/323-crash_fix.patch
new file mode 100644
index 000000000..2da3bf352
--- /dev/null
+++ b/package/madwifi/patches-testing/323-crash_fix.patch
@@ -0,0 +1,21 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -1999,11 +1999,13 @@
+ 	/* From this point onwards we can no longer find the node,
+ 	 * so no more references are generated
+ 	 */
+-	ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
+-	ieee80211_del_wds_node(nt, ni);
+-	IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-	node_table_leave_locked(nt, ni);
+-	IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
++	if (nt) {
++		ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
++		ieee80211_del_wds_node(nt, ni);
++		IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
++		node_table_leave_locked(nt, ni);
++		IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
++	}
+ 
+ 	/*
+ 	 * If node wasn't previously associated all
diff --git a/package/madwifi/patches-testing/324-reassoc.patch b/package/madwifi/patches-testing/324-reassoc.patch
new file mode 100644
index 000000000..7d1ade3dd
--- /dev/null
+++ b/package/madwifi/patches-testing/324-reassoc.patch
@@ -0,0 +1,31 @@
+Add a preliminary fix for the reassoc check, but disable reassoc entirely for now
+until we've figured out why it fails frequently.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -561,10 +561,9 @@
+ EXPORT_SYMBOL(ieee80211_ibss_merge);
+ 
+ static __inline int
+-ssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
++bssid_equal(const struct ieee80211_node *a, const struct ieee80211_node *b)
+ {
+-	return (a->ni_esslen == b->ni_esslen &&
+-		memcmp(a->ni_essid, b->ni_essid, a->ni_esslen) == 0);
++	return (memcmp(a->ni_bssid, b->ni_bssid, IEEE80211_ADDR_LEN) == 0);
+ }
+ 
+ /*
+@@ -596,8 +595,8 @@
+ 	 * Check if old+new node have the same ssid in which
+ 	 * case we can reassociate when operating in sta mode.
+ 	 */
+-	canreassoc = ((obss != NULL) &&
+-		(vap->iv_state == IEEE80211_S_RUN) && ssid_equal(obss, selbs));
++	canreassoc = 0; /* ((obss != NULL) &&
++		(vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+ 	vap->iv_bss = selbs;
+ 	IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+ 	if (obss != NULL)
diff --git a/package/madwifi/patches-testing/325-sta_node_leave.patch b/package/madwifi/patches-testing/325-sta_node_leave.patch
new file mode 100644
index 000000000..6b0dcb8e8
--- /dev/null
+++ b/package/madwifi/patches-testing/325-sta_node_leave.patch
@@ -0,0 +1,59 @@
+Drop stale AP nodes from the client list when disconnecting.
+Fixes some reassoc issues.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1352,7 +1352,7 @@
+ 				IEEE80211_SEND_MGMT(ni,
+ 					IEEE80211_FC0_SUBTYPE_DISASSOC,
+ 					IEEE80211_REASON_ASSOC_LEAVE);
+-				ieee80211_sta_leave(ni);
++				ieee80211_node_leave(ni);
+ 				break;
+ 			case IEEE80211_M_HOSTAP:
+ 				ieee80211_iterate_nodes(&ic->ic_sta,
+@@ -1362,6 +1362,7 @@
+ 				break;
+ 			}
+ 			goto reset;
++		case IEEE80211_S_AUTH:
+ 		case IEEE80211_S_ASSOC:
+ 			switch (vap->iv_opmode) {
+ 			case IEEE80211_M_STA:
+@@ -1380,7 +1381,6 @@
+ 		case IEEE80211_S_SCAN:
+ 			ieee80211_cancel_scan(vap);
+ 			goto reset;
+-		case IEEE80211_S_AUTH:
+ 		reset:
+ 			ieee80211_reset_bss(vap);
+ 			break;
+@@ -1436,7 +1436,7 @@
+ 			break;
+ 		case IEEE80211_S_RUN:		/* beacon miss */
+ 			if (vap->iv_opmode == IEEE80211_M_STA) {
+-				ieee80211_sta_leave(ni);
++				ieee80211_node_leave(ni);
+ 				vap->iv_flags &= ~IEEE80211_F_SIBSS;	/* XXX */
+ 				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
+ 					ieee80211_check_scan(vap,
+@@ -1487,7 +1487,7 @@
+ 				vap->iv_state = ostate;	/* stay RUN */
+ 				break;
+ 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
+-				ieee80211_sta_leave(ni);
++				ieee80211_node_leave(ni);
+ 				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+ 					/* try to reauth */
+ 					IEEE80211_SEND_MGMT(ni,
+@@ -1514,7 +1514,7 @@
+ 				IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
+ 			break;
+ 		case IEEE80211_S_RUN:
+-			ieee80211_sta_leave(ni);
++			ieee80211_node_leave(ni);
+ 			if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+ 				/* NB: caller specifies ASSOC/REASSOC by arg */
+ 				IEEE80211_SEND_MGMT(ni, arg ?
diff --git a/package/madwifi/patches-testing/326-bmiss_handling.patch b/package/madwifi/patches-testing/326-bmiss_handling.patch
new file mode 100644
index 000000000..0c7263050
--- /dev/null
+++ b/package/madwifi/patches-testing/326-bmiss_handling.patch
@@ -0,0 +1,102 @@
+Improve the beacon miss handling. Instead of just dropping the connection,
+send a directed probe request to the AP to see if it's still responding.
+Schedule a software beacon miss timer in this case, which adds a timeout
+for the APs probe response.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3369,12 +3369,17 @@
+ 			}
+ 
+ 			/* WDS/Repeater: re-schedule software beacon timer for 
+-			 * STA. */
+-			if ((vap->iv_state == IEEE80211_S_RUN) &&
+-			    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
+-				mod_timer(&vap->iv_swbmiss, 
++			 * STA. Reset consecutive bmiss counter as well */
++			IEEE80211_LOCK_IRQ(ic);
++			if (vap->iv_state == IEEE80211_S_RUN) {
++				vap->iv_bmiss_count = 0;
++				if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
++					mod_timer(&vap->iv_swbmiss,
+ 						jiffies + vap->iv_swbmiss_period);
++				else
++					del_timer(&vap->iv_swbmiss);
+ 			}
++			IEEE80211_UNLOCK_IRQ(ic);
+ 
+ 			/* If scanning, pass the info to the scan module.
+ 			 * Otherwise, check if it's the right time to do
+--- a/net80211/ieee80211_proto.c
++++ b/net80211/ieee80211_proto.c
+@@ -1213,6 +1213,8 @@
+ 	}
+ 	/* XXX locking */
+ 	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++		int count;
++
+ 		IEEE80211_DPRINTF(vap,
+ 			IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
+ 			"%s\n", "beacon miss");
+@@ -1225,6 +1227,29 @@
+ 		if (vap->iv_opmode != IEEE80211_M_STA ||
+ 		    vap->iv_state != IEEE80211_S_RUN)
+ 			continue;
++
++		IEEE80211_LOCK_IRQ(ic);
++		count = vap->iv_bmiss_count++;
++		if (count) {
++			/* if the counter was already above zero, reset it
++			 * here, since we're going to do the bmiss handling
++			 * in any case */
++			vap->iv_bmiss_count = 0;
++		} else {
++			/* schedule the software beacon miss timer, it will be
++			 * cancelled, if the probe request is acked */
++			mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
++		}
++		IEEE80211_UNLOCK_IRQ(ic);
++
++		if (!count) {
++			ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr,
++				vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid,
++				vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen,
++				NULL, 0);
++			continue;
++		}
++
+ 		if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
+ #ifdef ATH_SUPERG_DYNTURBO
+ 			/* 
+@@ -1621,14 +1646,14 @@
+ 		}
+ 
+ 		/* WDS/Repeater: Start software beacon timer for STA */
++		vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
++		vap->iv_swbmiss.data = (unsigned long) vap;
++		vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
++			vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
++
+ 		if (ostate != IEEE80211_S_RUN &&
+ 		    (vap->iv_opmode == IEEE80211_M_STA &&
+ 		     vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) {
+-			vap->iv_swbmiss.function = ieee80211_sta_swbmiss;
+-			vap->iv_swbmiss.data = (unsigned long) vap;
+-			vap->iv_swbmiss_period = IEEE80211_TU_TO_JIFFIES(
+-				vap->iv_ic->ic_bmissthreshold * ni->ni_intval);
+-
+ 			mod_timer(&vap->iv_swbmiss, jiffies + vap->iv_swbmiss_period);
+ 		}
+ 
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -292,6 +292,7 @@
+ 
+ 	struct timer_list iv_swbmiss;			/* software beacon miss timer */
+ 	u_int16_t iv_swbmiss_period; 			/* software beacon miss timer period */
++	u_int16_t iv_bmiss_count;			/* consecutive beacon miss counter */
+ 	struct ieee80211_nsparams iv_nsparams;		/* new state parameters for tasklet for stajoin1 */
+ 	struct IEEE80211_TQ_STRUCT iv_stajoin1tq; 	/* tasklet for newstate action called from stajoin1tq */
+ 	unsigned int iv_nsdone;				/* Done with scheduled newstate tasklet */
diff --git a/package/madwifi/patches-testing/327-rssi_disconnect.patch b/package/madwifi/patches-testing/327-rssi_disconnect.patch
new file mode 100644
index 000000000..b7e406cb0
--- /dev/null
+++ b/package/madwifi/patches-testing/327-rssi_disconnect.patch
@@ -0,0 +1,91 @@
+Add an optional threshold for low-rssi disconnection. This can be useful
+when letting wpa_supplicant control roaming.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
+--- a/net80211/ieee80211_ioctl.h
++++ b/net80211/ieee80211_ioctl.h
+@@ -656,6 +656,8 @@
+ 	IEEE80211_PARAM_PROTMODE_RSSI		= 85,	/* RSSI Threshold for enabling protection mode */
+ 	IEEE80211_PARAM_PROTMODE_TIMEOUT	= 86,	/* Timeout for expiring protection mode */
+ 	IEEE80211_PARAM_BGSCAN_THRESH		= 87,	/* bg scan rssi threshold */
++	IEEE80211_PARAM_RSSI_DIS_THR	= 88,	/* rssi threshold for disconnection */
++	IEEE80211_PARAM_RSSI_DIS_COUNT	= 89,	/* counter for rssi threshold */
+ };
+ 
+ #define	SIOCG80211STATS			(SIOCDEVPRIVATE+2)
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -2832,6 +2832,12 @@
+ 	case IEEE80211_PARAM_ROAM_RATE_11G:
+ 		vap->iv_roam.rate11g = value;
+ 		break;
++	case IEEE80211_PARAM_RSSI_DIS_THR:
++		vap->iv_rssi_dis_thr = value;
++		break;
++	case IEEE80211_PARAM_RSSI_DIS_COUNT:
++		vap->iv_rssi_dis_max = value;
++		break;
+ 	case IEEE80211_PARAM_UAPSDINFO:
+ 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ 			if (ic->ic_caps & IEEE80211_C_UAPSD) {
+@@ -3220,6 +3226,12 @@
+ 	case IEEE80211_PARAM_ROAM_RATE_11G:
+ 		param[0] = vap->iv_roam.rate11g;
+ 		break;
++	case IEEE80211_PARAM_RSSI_DIS_THR:
++		param[0] = vap->iv_rssi_dis_thr;
++		break;
++	case IEEE80211_PARAM_RSSI_DIS_COUNT:
++		param[0] = vap->iv_rssi_dis_max;
++		break;
+ 	case IEEE80211_PARAM_UAPSDINFO:
+ 		if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ 			if (IEEE80211_VAP_UAPSD_ENABLED(vap))
+@@ -5770,6 +5782,14 @@
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rate11g_x2" },
+ 	{ IEEE80211_PARAM_ROAM_RATE_11G,
+ 	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rate11g_x2" },
++	{ IEEE80211_PARAM_RSSI_DIS_THR,
++	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_disthr" },
++	{ IEEE80211_PARAM_RSSI_DIS_THR,
++	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_disthr" },
++	{ IEEE80211_PARAM_RSSI_DIS_COUNT,
++	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rssi_discnt" },
++	{ IEEE80211_PARAM_RSSI_DIS_COUNT,
++	  0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rssi_discnt" },
+ 	{ IEEE80211_PARAM_UAPSDINFO,
+ 	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "uapsd" },
+ 	{ IEEE80211_PARAM_UAPSDINFO,
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -3234,6 +3234,17 @@
+ 
+ 			/* When rssi is low, start doing bgscans more frequently to allow
+ 			 * the supplicant to make a better switching decision */
++			if ((vap->iv_rssi_dis_thr > 0) && (vap->iv_rssi_dis_max > 0)) {
++				if ((rssi > 0) && (rssi < vap->iv_rssi_dis_thr)) {
++					if (++vap->iv_rssi_dis_trig > vap->iv_rssi_dis_max) {
++						vap->iv_rssi_dis_trig = 0;
++						ieee80211_node_leave(ni);
++						return 0;
++					}
++				} else {
++					vap->iv_rssi_dis_trig = 0;
++				}
++			}
+ 			if ((rssi < vap->iv_bgscanthr) &&
+ 					(!vap->iv_bgscanthr_next ||
+ 						!time_before(jiffies, vap->iv_bgscanthr_next)) &&
+--- a/net80211/ieee80211_var.h
++++ b/net80211/ieee80211_var.h
+@@ -233,6 +233,9 @@
+ 	u_int iv_bgscanintvl;				/* bg scan min interval */
+ 	u_int iv_bgscanthr;					/* bg scan rssi threshold */
+ 	u_int iv_bgscantrintvl;				/* bg scan trigger interval */
++	u_int iv_rssi_dis_thr;				/* rssi disassoc threshold */
++	u_int iv_rssi_dis_max;				/* max beacons below disconnect threshold */
++	u_int iv_rssi_dis_trig;				/* rssi disassoc trigger count */
+ 	unsigned long iv_bgscanthr_next;		/* last trigger for bgscan */
+ 	u_int iv_scanvalid;				/* scan cache valid threshold */
+ 	struct ieee80211_roam iv_roam;			/* sta-mode roaming state */
diff --git a/package/madwifi/patches-testing/328-memory_alloc.patch b/package/madwifi/patches-testing/328-memory_alloc.patch
new file mode 100644
index 000000000..ff60dbdb3
--- /dev/null
+++ b/package/madwifi/patches-testing/328-memory_alloc.patch
@@ -0,0 +1,11 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -504,7 +504,7 @@
+ 
+ 	/* Allocate space for dynamically determined maximum VAP count */
+ 	sc->sc_bslot = 
+-		kzalloc(ath_maxvaps * sizeof(struct ieee80211vap), GFP_KERNEL);
++		kzalloc(ath_maxvaps * sizeof(struct ieee80211vap *), GFP_KERNEL);
+ 
+ 	/*
+ 	 * Cache line size is used to size and align various
diff --git a/package/madwifi/patches-testing/329-turbo_chansearch.patch b/package/madwifi/patches-testing/329-turbo_chansearch.patch
new file mode 100644
index 000000000..ba8b01c12
--- /dev/null
+++ b/package/madwifi/patches-testing/329-turbo_chansearch.patch
@@ -0,0 +1,10 @@
+--- a/net80211/ieee80211.c
++++ b/net80211/ieee80211.c
+@@ -695,6 +695,7 @@
+ 	int i;
+ 
+ 	/* Brute force search */
++	flags &= IEEE80211_CHAN_ALLTURBO;
+ 	for (i = 0; i < ic->ic_nchans; i++) {
+ 		c = &ic->ic_channels[i];
+ 		if (c->ic_freq == freq &&
diff --git a/package/madwifi/patches-testing/330-bstuck_thresh.patch b/package/madwifi/patches-testing/330-bstuck_thresh.patch
new file mode 100644
index 000000000..5f864bb59
--- /dev/null
+++ b/package/madwifi/patches-testing/330-bstuck_thresh.patch
@@ -0,0 +1,52 @@
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -354,6 +354,7 @@
+ static int ath_outdoor = AH_FALSE;		/* enable outdoor use */
+ static int ath_xchanmode = AH_TRUE;		/* enable extended channels */
+ static int ath_maxvaps = ATH_MAXVAPS_DEFAULT;   /* set default maximum vaps */
++static int bstuck_thresh = BSTUCK_THRESH;       /* Stuck beacon count required for reset */
+ static char *autocreate = "sta";
+ static char *ratectl = DEF_RATE_CTL;
+ static int rfkill = 0;
+@@ -397,6 +398,7 @@
+ #ifdef ATH_CAP_TPC
+ MODULE_PARM(hal_tpc, "i");
+ #endif
++MODULE_PARM(bstuck_thresh, "i");
+ MODULE_PARM(autocreate, "s");
+ MODULE_PARM(ratectl, "s");
+ #else
+@@ -410,6 +412,7 @@
+ #ifdef ATH_CAP_TPC
+ module_param(hal_tpc, int, 0600);
+ #endif
++module_param(bstuck_thresh, int, 0600);
+ module_param(autocreate, charp, 0600);
+ module_param(ratectl, charp, 0600);
+ #endif
+@@ -422,6 +425,7 @@
+ MODULE_PARM_DESC(hal_tpc, "Disables manual per-packet transmit power control and "
+ 		"lets this be managed by the HAL.  Default is OFF.");
+ #endif
++MODULE_PARM_DESC(bstuck_thresh, "Override default stuck beacon threshold");
+ MODULE_PARM_DESC(autocreate, "Create ath device in "
+ 		"[sta|ap|wds|adhoc|ahdemo|monitor] mode. defaults to sta, use "
+ 		"'none' to disable");
+@@ -5239,7 +5243,7 @@
+ 		DPRINTF(sc, ATH_DEBUG_BEACON_PROC,
+ 			"Missed %u consecutive beacons (n_beacon=%u)\n",
+ 			sc->sc_bmisscount, n_beacon);
+-		if (sc->sc_bmisscount > BSTUCK_THRESH)
++		if (sc->sc_bmisscount > bstuck_thresh)
+ 			ATH_SCHEDULE_TQUEUE(&sc->sc_bstucktq, needmark);
+ 		return;
+ 	}
+@@ -5410,7 +5414,7 @@
+ 	 *     check will be true, in which case return
+ 	 *     without resetting the driver.
+ 	 */
+-	if (sc->sc_bmisscount <= BSTUCK_THRESH)
++	if (sc->sc_bmisscount <= bstuck_thresh)
+ 		return;
+ 	EPRINTF(sc, "Stuck beacon; resetting (beacon miss count: %u)\n",
+ 		sc->sc_bmisscount);
diff --git a/package/madwifi/patches-testing/331-linux24_fix.patch b/package/madwifi/patches-testing/331-linux24_fix.patch
new file mode 100644
index 000000000..1d9a2d06c
--- /dev/null
+++ b/package/madwifi/patches-testing/331-linux24_fix.patch
@@ -0,0 +1,15 @@
+--- a/ath_hal/Makefile
++++ b/ath_hal/Makefile
+@@ -79,10 +79,11 @@
+ quiet_cmd_uudecode = UUDECODE $@
+       cmd_uudecode = $(obj)/uudecode -o $@ $<
+ 
+-$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+ ifdef LINUX24
++$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+ 	$(Q)$(obj)/uudecode -o $@ $<
+ else
++$(obj)/$(TARGET).hal.o: $(HAL)/public/$(TARGET).hal.o.uu $(obj)/uudecode
+ 	$(call if_changed,uudecode)
+ endif
+ # Replace as many hashed names as possible with meaningful
diff --git a/package/madwifi/patches-testing/332-retransmit_check.patch b/package/madwifi/patches-testing/332-retransmit_check.patch
new file mode 100644
index 000000000..ec1fcf9c7
--- /dev/null
+++ b/package/madwifi/patches-testing/332-retransmit_check.patch
@@ -0,0 +1,22 @@
+--- a/net80211/ieee80211.h
++++ b/net80211/ieee80211.h
+@@ -174,8 +174,6 @@
+ #define	IEEE80211_SEQ_SEQ_MASK			0xfff0
+ #define	IEEE80211_SEQ_SEQ_SHIFT			4
+ 
+-#define	IEEE80211_SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
+-
+ #define	IEEE80211_NWID_LEN			32
+ 
+ #define	IEEE80211_QOS_TXOP			0x00ff
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -406,7 +406,7 @@
+ 				tid = 0;
+ 			rxseq = le16toh(*(__le16 *)wh->i_seq);
+ 			if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
+-			    IEEE80211_SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) {
++			    (rxseq == ni->ni_rxseqs[tid])) {
+ 				/* duplicate, discard */
+ 				IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+ 					bssid, "duplicate",
diff --git a/package/madwifi/patches-testing/333-hal_init_msg.patch b/package/madwifi/patches-testing/333-hal_init_msg.patch
new file mode 100644
index 000000000..1369dcfc1
--- /dev/null
+++ b/package/madwifi/patches-testing/333-hal_init_msg.patch
@@ -0,0 +1,30 @@
+--- a/ath_hal/ah_os.c
++++ b/ath_hal/ah_os.c
+@@ -1136,9 +1136,6 @@
+  * Module glue.
+  */
+ #include "version.h"
+-#if 0
+-static char *dev_info = "ath_hal";
+-#endif
+ 
+ MODULE_AUTHOR("Errno Consulting, Sam Leffler");
+ MODULE_DESCRIPTION("Atheros Hardware Access Layer (HAL)");
+@@ -1172,7 +1169,7 @@
+ static int __init
+ init_ath_hal(void)
+ {
+-	const char *sep;
++	const char *sep = "";
+ 	int i;
+ #ifdef MMIOTRACE
+ 	kmmio_logmsg = _kmmio_logmsg;
+@@ -1181,7 +1178,7 @@
+ 	ifxmips_emulate = ifxmips_has_brn_block();
+ #endif
+ 
+-	sep = "";
++	printk(KERN_INFO "hal: %s (", ath_hal_version);
+ 	for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
+ 		printk("%s%s", sep, ath_hal_buildopts[i]);
+ 		sep = ", ";